美文网首页ReactNative学习记录
04 ReactNavigation入门详解(参照官网文档)(上

04 ReactNavigation入门详解(参照官网文档)(上

作者: 与之书 | 来源:发表于2018-03-13 17:28 被阅读294次

以下内容参照StackNavigator官网文档 链接

Hello React Navigation

  1. 参照官网,如果要支持安卓,要先下载react-navigation这个库,在工程路径下执行:
npm install --save react-navigation
// 如果安装了yarn 也可以使用以下命令
yarn add react-navigation
  1. React Navigation中用到了StackNavigator,即创建了一个类似于浏览器的历史栈的对象。StackNavigator和web历史栈的一个关键区别是可以手势和动画效果。

  2. 创建基本导航栈

import React from 'react';
import { View, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';

class HomeScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
      </View>
    );
  }
}

export default StackNavigator({
  Home: {   // 这个名字任意
    screen: HomeScreen, // 必须有screen这个组件
  },
});

因为StackNavigator()返回一个组件,所以可以直接通过export导出。显示这个栈中的内容更,目前只有一个空的导航,和中间的文字。
在ReactNative中,在App.js中export的组件是整个App的入口(或者叫根组件),通常不会直接导出一个'导航栈'组件,而是用另外一个组件渲染'导航栈'组件。修改如下:

const RootStack = StackNavigator({
  Home: {
    screen: HomeScreen,
  },
});

export default class App extends React.Component {
  render() {
    return <RootStack />;
  }
}
  1. 添加第二屏
class DetailsScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
      </View>
    );
  }
}

const RootStack = StackNavigator(
  {
    Home: {
      screen: HomeScreen,
    },
    Details: {
      screen: DetailsScreen,
    },
  },
  {
    initialRouteName: 'Home',
  }
);

第一个参数,表示导航栈内有哪些视图;第二个是配置参数(可选)
修改initialRouteName后面的名称,可以发现初始化的页面不同。
下节讨论如何在双屏间切换。

双屏间切换

  1. 在主屏设置Button,并添加点击,关联到this.props.navigation.navigate('Details')
import React from 'react';
import { Button, View, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';

class HomeScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
        <Button
          title="Go to Details"
          onPress={() => this.props.navigation.navigate('Details')}
        />
      </View>
    );
  }
}

this.props.navigation,这个属性会被设置到所有StackNavigator中的页面
navigate('Details'),将页面名称传入该方法,可以跳转到指定页面
只能跳转到StackNavigator中的界面,如果该名称传入错误,什么也不会发生。
如果在Details页面再添加一个Button跳转到Details页面,页面会一直被添加。

  1. StackNavigator会在非首屏提供一个返回箭头,提供返回操作。也可以通过添加按钮关联goback返回。此外,StackNavigator自动关联了安卓的返回键,点击设备的返回键也可以返回。
class DetailsScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Button 
          title = 'GO TO DETAIL AGAIN'
          onPress = {()=>this.props.navigation.navigate('Details')}         
        />
        <Button
          title="Go back"
          onPress={() => this.props.navigation.goBack()}
        />
      </View>
    );
  }
}

测试发现,自己设置返回正常,但点击头部箭头返回在MX4上很慢,并不是不执行,但是要间隔很久,实测用了12s。。。目前没有找到原因。(看看自定义能不能解决)
运行时遇到一个Unknown error: not all success patterns were matched错误,重新加载也不行,直接运行也不行。 用命令行跑了一下,发现找不到设备。。。重新拔插了一下usb就好了。

传递参数

  1. 通过在调用navigate方法时传入一个对象
this.props.navigation.navigate('RouteName', { /* params go here */ })
  1. 读取参数
this.props.navigation.state.params
class HomeScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
        <Button
          title="Go to Details"
          onPress={() => {
            /* 1. Navigate to the Details route with params */
            this.props.navigation.navigate('Details', {
              itemId: 86,
              otherParam: 'anything you want here',
            });
          }}
        />
      </View>
    );
  }
}

class DetailsScreen extends React.Component {
  render() {
    /* 2. Read the params from the navigation state */
    const { params } = this.props.navigation.state;
    const itemId = params ? params.itemId : null;
    const otherParam = params ? params.otherParam : null;

    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Text>itemId: {JSON.stringify(itemId)}</Text>
        <Text>otherParam: {JSON.stringify(otherParam)}</Text>
        <Button
          title="Go to Details... again"
          onPress={() => this.props.navigation.navigate('Details')}
        />
        <Button
          title="Go back"
          onPress={() => this.props.navigation.goBack()}
        />
      </View>
    );
  }
}

自定义header bar

  1. 每个组件有一个静态属性叫navigationOptions,可以通过这个配置一些参数,例如title (ios默认会居中,android居左)
class HomeScreen extends React.Component {
  static navigationOptions = {
    title: 'Home',
  };
  /* render function, etc */
}

class DetailsScreen extends React.Component {
  static navigationOptions = {
    title: 'Details',
  };
  /* render function, etc */
}
  1. 将this.props放入navigationOptions中使用看起来很方便,但因为这是个静态属性,所以实际上并不会关联到任何实例,自然也不会有props属性。这里需要将navigationOptions变成一个方法,React Navigation会通过一个包含{navigation, navigationOptions, screenProps}的对象调用它。

  2. 传递参数设置navigationOptions

class DetailsScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    // 注意params是带大括号的
    const { params } = navigation.state;
    
    return {
      title: params ? params.otherParam : 'A Nested Details Screen',
    }
  };

  /* render function, etc */
}

The argument that is passed in to the navigationOptions function is an object with the following properties:
navigation - The navigation prop for the screen, with the screen's route at navigation.state.
screenProps - The props passing from above the navigator component(上层组件传过来的参数)
navigationOptions - The default or previous options that would be used if new values are not provided
上面只用到了navigation属性

  1. 在当前屏幕对navigationOptions进行更新
<Button
    title="Update the title"
    onPress={() => this.props.navigation.setParams({otherParam: 'Updated!'})}
  />

通过setParams设置了一个新的对象

  1. 调整头部样式
    主要用到三个属性

headerStyle:设置包裹头部view的样式,可以设置背景颜色
headerTintColor: 渲染返回键、标题的颜色。
headerTitleStyle: 设置文字、字体、粗细(fontWeight)?

class HomeScreen extends React.Component {
  static navigationOptions = {
    title: 'Home',
    headerStyle: {
      backgroundColor: '#f4511e',
    },
    headerTintColor: '#fff',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
  };

  /* render function, etc */
}

这种设置方式只对当前页面有效。

  1. 如果要配置对所有导航页都有效的样式,应该在StackNavigator的第二个参数中配置
const RootStack = StackNavigator(
  {
    Home: {
      screen: HomeScreen,
    },
    Details: {
      screen: DetailsScreen,
    },
  },
  {
    initialRouteName: 'Home',
    /* The header config from HomeScreen is now here */
    navigationOptions: {
      headerStyle: {
        backgroundColor: '#f4511e',
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
        fontWeight: 'bold',
      },
    },
  }
);

这样所有的样式就一样了,如果某个页面要设置特殊样式,可以单独设置。也可以通过将公共的navigationOptions 通过对象传入进行修改。

  1. 自定义一个组件作为标题
// 定义一个标题
class LogoTitle extends React.Component {
  render() {
    return (
      <Text style ={ {flex:1, fontSize:30,color:'green',textAlign:'center'}}>
      标题
      </Text>
    );
  }
}

class HomeScreen extends React.Component {
 
  static navigationOptions = {
    // title: 'Home',
    headerTitle:<LogoTitle/>,
  };
  ...以下省略...

相关API可以查看StackNavigator reference

代码地址

相关文章

网友评论

  • Cheriez:请问下 我用vscode 调试的时候 也报错了 :Unknown error: not all success patterns were matched错误,亲指的重新拔插了一下usb是?
    Cheriez:@与之书 明白了 ~~ 感谢!
    与之书:@Cheriez 遇到这种的是先用命令行跑一下 就是工程目录下 react-native run-android 会有具体的报错信息 我之前是设备没连接 usb有点问题

本文标题:04 ReactNavigation入门详解(参照官网文档)(上

本文链接:https://www.haomeiwen.com/subject/ylazfftx.html