美文网首页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