当前位置:

React Navigation 4.x

访客 2024-04-23 980 0

近期将项目中的reactnative升级到了0.60.x版本,同步的也将ReactNavigation升级到了4.x。这篇博客记录了4.x版本的一些基本用法以及在实现项目中一些常见功能的实现,其中rn基于0.60版本。

安装

4.x版本从react-navigation中移除了各类导航器,同时还依赖了一些其他的包需要手动安装。

npminstallreact-navigationreact-native-reanimatedreact-native-gesture-handlerreact-native-screensreact-native-safe-area-context

rn0.60版本之后,安装完成之后会自动link,低版本安装过程见官网说明。

Android端需要手动进行一些修改,编辑android/app/build.gradle,在dependencies中添加如下内容:

implementation'androidx.appcompat:appcompat:1.1.0-rc01'implementation'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'

编辑Android中的MainActivity.java,添加如下内容:

packagecom.reactnavigation.example;importcom.facebook.react.ReactActivity;importcom.facebook.react.ReactActivityDelegate;importcom.facebook.react.ReactRootView;importcom.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;publicclassMainActivityextendsReactActivity{@OverrideprotectedStringgetMainComponentName(){return"Example";}@OverrideprotectedReactActivityDelegatecreateReactActivityDelegate(){returnnewReactActivityDelegate(this,getMainComponentName()){@OverrideprotectedReactRootViewcreateRootView(){returnnewRNGestureHandlerEnabledRootView(MainActivity.this);}};}}

最后在index.js或者app.js中导入react-native-gesture-handler依赖即可。

import'react-native-gesture-handler';基本使用

4.x版本移除了各类导航器,需要手动安装,这里安装一下StackNavigatorBottomTabNavigator

npminstallreact-navigation-stack@react-native-community/masked-viewreact-navigation-tabs

添加三个页面组件:

constHome=props=>{const{navigation}=propsreturn(<View><TouchableOpacityonPress={()=>navigation.push('Second')}><View><Text>Secondpage</Text></View></TouchableOpacity></View>)}constMy=()=>{return(<View><Text>My</Text></View>)}constSecond=()=>{return(<View><Text>Second</Text></View>)}

创建导航器,这一部分写法和之前一样:

constMainTab=createBottomTabNavigator({Home,My,})constAppStack=createStackNavigator({Main:{screen:MainTab,},Second,})exportdefaultfunctionApp(){constAppContainer=createAppContainer(AppStack)return<AppContainer/>}调整TabNavigatorHeader标题

从上图可以看到,Home和My页面顶部标题都是现实的Main,因为这两个页面都在BottomTabNavigator中,共用了一个Header。我们可以通过Main页面的navigationOptions来动态修改标题:

Main:{screen:MainTab,navigationOptions:({navigation})=>{const{routeName}=navigation.state.routes[navigation.state.index]//YoucandowhateveryoulikeheretopickthetitlebasedontheroutenameconstheaderTitle=routeNamereturn{headerTitle,}}}

这里直接使用了routeName作为标题,也可以根据routeName匹配其他的标题文字。效果如下:

添加Tabbar图标

通过BottomTabNavigatornavigationOptions中的tabBarIcon属性可以设置Tabbar的图标。

首先实现一个TabbarIcon组件,根据routeName返回相应的图片,同时图片会读取tintColor属性设置颜色:

constIMAGES={Home:require('./assets/icons/home.png'),My:require('./assets/icons/my.png'),}constTabbarIcon=({routeName,tintColor})=>{return(<Imagesource={IMAGES[routeName]}style={[styles.image,{tintColor:tintColor}]}resizeMode="contain"/>)}conststyles=StyleSheet.create({image:{height:24,},})

然后通过BottomTabNavigatordefaultNavigationOptions属性设置不同页面的图标:

defaultNavigationOptions:({navigation})=>{const{routeName}=navigation.statereturn{tabBarIcon:props=><TabbarIcon{...props}routeName={routeName}/>,}}

还可以通过tabBarOptions设置激活和未激活的颜色:

tabBarOptions:{inactiveTintColor:'rgba(0,0,0,0.45)',activeTintColor:'#722ed1',}统一路由风格

StackNavigator在Android中的表现和iOS中存在一些差异,通过暴露的一些配置项我们可以统一风格,这里统一使用iOS的风格。

首先实现一个HeaderBackImage组件,统一返回图标:

constIS_IOS=Platform.OS==='ios'exportdefaultprops=>{return(<Viewstyle={styles.imgContainer}><Imagesource={require('./assets/icons/icon_back.png')}style={[styles.image,{tintColor:props.tintColor}]}{...props}/></View>)}conststyles=StyleSheet.create({imgContainer:{paddingRight:IS_IOS?6:15,paddingLeft:IS_IOS?15:0,},image:{backgroundColor:'transparent',height:16,width:10,resizeMode:'contain',},})

修改StackNavigator配置:

defaultNavigationOptions:{headerStyle:{elevation:0,//移除AndroidHeader阴影shadowOpacity:0,//移除iOSHeader阴影},headerBackImage:HeaderBackImage,headerTitleAlign:'center',//Android标题居中headerBackTitleVisible:false,//隐藏iOS返回按钮标题headerPressColorAndroid:'transparent',//移除Android点击返回按钮效果cardStyleInterpolator:CardStyleInterpolators.forHorizontalIOS,//切换路由时水平动画headerStyleInterpolator:HeaderStyleInterpolators.forUIKit,//切换路时Header动画},headerMode:'float',//页面共用一个Header,切换时应用动画沉浸式状态栏

之前我写过一篇关于实现沉浸式状态栏的博客,在4.x版本中实现该功能变得更加方便。

纯色

首先我们给Header添加一个背景色看看默认是什么效果。

headerStyle:{backgroundColor:'#722ed1',},headerTintColor:'#fff',

可以看到Android端状态栏依旧是灰色。我们可以设置StatusBar的属性来实现沉浸式:

<><StatusBarbackgroundColor="transparent"translucent/><AppContainer/></>

可以看到设置了translucent之后,内容并没有往上移动到状态,4.x版本默认处理了这种情况。

背景图

有时页面顶部有一张背景图或者整个页面有个全屏背景,这时我们就需要Header透明并且内容能衍生到状态栏底部。

我们先修改Second页面,添加一个背景图片:

constSecond=()=>{return(<ImageBackgroundstyle={{flex:1}}source={require('../../assets/img/bg.jpg')}><Text>Ihaveafullscreenbackgroundimage</Text></ImageBackground>)}

可以看到图片并没有撑满整个屏幕,设置headerTransparent属性为true可以使Header透明并浮在页面上,这样内容就会撑满。

Second.navigationOptions={headerTransparent:true,}

此时虽然全屏了,但是内容却跑到Header底部除了,我们需要添加上边距预留出Header的位置,通过useHeaderHeight可以获取到Header的高度。

import{useHeaderHeight}from'react-navigation-stack'constheaderHeight=useHeaderHeight()处理状态栏文字

RN中切换到不同的页面,可能需要显示不能颜色的文字(深色、浅色),在之前的博客中介绍了使用高阶组件的方法,监听navigation的willFocus事件切换。4.x版本中仍需要使用此方案,不过这次通过hook来实现。

//useStatusBar.jsimport{useEffect}from'react'import{StatusBar}from'react-native'constuseStatusBar=(navigation,barStyle)=>{useEffect(()=>{constonWillFocus=()=>{StatusBar.setBarStyle(barStyle)}StatusBar.setBarStyle(barStyle)constlistener=navigation.addListener('willFocus',onWillFocus)return()=>listener.remove()},[])}exportdefaultuseStatusBar

当页面挂载之后设置状态栏的风格,后续当从其他页面返回时会触发willFocus事件。

发表评论

  • 评论列表
还没有人评论,快来抢沙发吧~