react-navigation导航器

  • 2019 年 10 月 5 日
  • 筆記

https://reactnavigation.org/ ——源于React Native社区对基于Javascript的可扩展且使用简单的导航解决方案的需求 。

和h5用a标签来跳转不太一样的是,rn必须依赖导航器跳转。导航器也可以看成是一个普通的React组件,你可以通过导航器来定义你的APP中的导航结构。导航还可以渲染通用元素,例如可以配置的标题栏和选项卡栏。

react-natvigation自开源以来。在短短不到3个月的时间,github上星数已达4000+。它是Fb推荐使⽤库, 并且在React Native当前最新版本0.44中将Navigator删除。react-navigation据称有原生般的性能体验效果。可能会成为未来React Native导航组件的主流军 。

可以粗略地理解,navigation就是rn版的router。

安装

注:从19年7月到现在不到两个月,navigation有了大的更新。看官网文档也未必有用。经过笔者一天的踩坑,想要成功运行请严格执行以下操作。其它不能保证。 请确保项目绝对路径无中文。

安装(0.60-)时除了本体,还需要一个手势库:

yarn add [email protected]  yarn [email protected]

接着需要手动link它(关联原生):

react-native link react-native-gesture-handler

此时ios已经可以跑了。但安卓配置还没完。把以下代码添加到 MainActivity.java

package com.rn;    import com.facebook.react.ReactActivity;  // add  import com.facebook.react.ReactActivityDelegate;  import com.facebook.react.ReactRootView;  import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;  // end add  public class MainActivity extends ReactActivity {        /**       * Returns the name of the main component registered from JavaScript.       * This is used to schedule rendering of the component.       */      @Override      protected String getMainComponentName() {          return "rn";      }      // add      @Override      protected ReactActivityDelegate createReactActivityDelegate() {          return new ReactActivityDelegate(this, getMainComponentName()) {              @Override              protected ReactRootView createRootView() {              return new RNGestureHandlerEnabledRootView(MainActivity.this);              }          };      }      // end add  }

到了这一步,就可以启动应用了。

补白

概念
在开始学习导航器之前,我们需要了了解两个和导航有关的概念:
  • Screen navigation prop(屏幕导航属性):通过navigation可以完成屏幕之间的调度操作,例如打开另一个屏幕
  • Screen navigationOptions(屏幕导航选项):通过navigationOptions可以定制导航器显示屏幕的方式(例如:头部标题,选项卡标签等)
导航器类型

在react-navigation中有以下类型的导航器:

  • createStackNavigator:类似普通的Navigator,导航上⽅导航栏
  • createTabNavigator:已弃用,使⽤createBottomTabNavigator、 createMaterialTopTabNavigator替代
  • createBottomTabNavigator:相当于IOS里面的UITabBarController,屏幕下⽅的标签
  • createMaterialTopTabNavigator:屏幕顶部的材料设计主题标签栏
  • createDrawerNavigator:抽屉效果,侧边滑出
  • createSwitchNavigator:SwitchNavigator的用途是一次只显示⼀个⻚页⾯面

你可以通过以上几种导航器来创建你的APP,可以是其中一个,也可以多个组合,这个可以根据具体的应 ⽤场景并结合每⼀个导航器器的特性进⾏选择。

项目管理

创建一个src目录,如图:

在page下写几个页面(HomePage,MyPage,HotPage):

import React,{Component} from 'react';  import {View,Text,StyleSheet} from 'react-native';    export default class HomePage extends Component{        render(){          return (            <View style={styles.container}>                <Text style={styles.text}>HomePage</Text>            </View>          )        }  }    const styles=StyleSheet.create({      container:{          flex:1,          justifyContent:'center',          alignItems:'center',          backgroundColor:'#f5f5f5'      },      text:{          fontSize:26      }  })

在Navigator下新建AppNavigator.js:

import {createAppContainer} from 'react-navigation';  import { createStackNavigator } from 'react-navigation-stack';    import HomePage from '../Pages/HomePage';  import MyPage from '../Pages/MyPage';  import HotPage from '../Pages/HotPage';    const AppNavigator=createStackNavigator({      Home:{          screen:HomePage      },      My:{          screen:MyPage      },      Hot:{          screen:HotPage      }  });    export default createAppContainer(AppNavigator);

跑一下程序,看到:

就算运行成功了。

基本使用(重点)

这里使用堆栈导航。

createStackNavigator 提供APP屏幕之间切换的能⼒,它是以栈的形式还管理屏幕之间的切换,新切换到的屏幕会放在栈的顶部。

createStackNavigator API

createStackNavigator(RouteConfigs, StackNavigatorConfig):
  • RouteConfigs (必选):路路由配置对象是从路路由名称到路路由配置的映射,告诉导航器器该路路由呈现什什 么。
  • StackNavigatorConfig (可选):配置导航器器的路路由(如:默认⾸首屏,navigationOptions,paths 等)样式(如,转场模式mode、头部模式等)。

在HomePage引入button,给它加个 onPress事件:

<View style={styles.container}>                  <Button                      title={'跳转到我的页面'}                      onPress={()=>{                        console.log(this.props)                      }}                  ></Button>                <Text style={styles.text}>HotPage</Text>            </View>

然后页面上出现一个button,点击一下,控制台弹出了以下内容:

通过navigation。封装了一系列方法。

  • navigate:跳转到其他界⾯
  • state:屏幕的当前state
  • setParams:改变路由的params
  • goBack:关闭当前屏幕
  • disPatch:向路由发送一个action
  • addListener:订阅导航生命周期的更新
  • isFocused:true标识屏幕获取了焦点
  • getParam:获取具有回退的特定参数
  • dangerouslyGetParent:返回父导航器

注意:一个navigation有可能没有navigate、setParams以及goBack,只有state与dispatch,所以在使用navigate时要进⾏判断,如果没有navigate可以使⽤navigation去dispatch一个新的action。

跳转

接收两个参数,第一个是定义好的路由名,第二个是页面参数。

<Button      title={'跳转到我的页面'}      onPress={()=>{        console.log(this.props)        this.props.navigation.navigate('My',{          title:'我的'        })      }}  ></Button>  <Button      title={'跳转到热门页面'}      onPress={()=>{        console.log(this.props)        this.props.navigation.navigate('Hot',{          title:'热门'        })      }}  ></Button>    <Text style={styles.text}>HomePage</Text>
返回

留意右上角,原生按钮已经支持返回。但我想自定义一个返回按钮的话可以直接用goBack方法:

<Button      title={'返回'}      onPress={()=>{          this.props.navigation.goBack()    }}  ></Button>

goBack:function goBack(key):我们可以借助goBack返回到上⼀页或者路由栈的指定⻚面。

key标识你要返回到⻚面的⻚面标识符,如:id-1517035332238-4,不是routeName。可以通过指定⻚面的navigation.state.key来获取⻚页⾯面的标识 key必传,不传默认返回上一页

传参

现在我想定义一个参数给下一个也页面,可以这么做:

<Button      title={'跳转到热门页面'}    onPress={()=>{        console.log(this.props)      this.props.navigation.navigate('Hot',{          title:'热门'      })    }}   ></Button>

在被跳转的页面可以通过getParam方法获取:

<Text style={styles.text}>{this.props.navigation.getParam('title')}</Text>
在页面中定义标题

留意到以下模拟器中,

这些都是可以自己定义的。

回到AppNavigator,我可以给首页加个标题:

Home:{          screen:HomePage,          // 导航器配置:          navigationOptions:{              // 让导航栏为空              // header:null              // 设置导航栏标题              headerTitle:'首页'          }      },
优雅地定义标题

你还可以自定义navigationOptions:

export default class MyPage extends Component{      static navigationOptions={          title:'我的'      }        render(){          return (            <View style={styles.container}>                <Text style={styles.text}>{this.props.navigation.getParam('title')}</Text>            </View>          )        }  }

接下来可以组合页面穿参来用:

static navigationOptions=({navigation})=>{          return {              headerTitle:navigation.getParam('title')          }      }

!image-20190914172536556

更新参数

有getParam就有setParams。

export default class MyPage extends Component{      static navigationOptions=({navigation})=>{          return {              headerTitle:navigation.getParam('title')          }      }        render(){          return (            <View style={styles.container}>                <Text style={styles.text}>{this.props.navigation.getParam('title')}</Text>                <Button                      title={'更新页面参数'}                      onPress={()=>{                        this.props.navigation.setParams({                            title:'aaa'                        })                      }}                  ></Button>            </View>          )        }  }

一点击,你的title就全变成了aaa。

注意:navigation.setParams改变的是当前页⾯的Params,如果要改变其他⻚面的Params可以通过 NavigationActions.setParams完成。