这篇文章主要围绕ReactNative未来导航者:react-navigation使用详解和进阶篇展开,旨在为您提供一份详细的参考资料。我们将全面介绍ReactNative未来导航者:react-na
这篇文章主要围绕React Native未来导航者:react-navigation 使用详解和进阶篇展开,旨在为您提供一份详细的参考资料。我们将全面介绍React Native未来导航者:react-navigation 使用详解的优缺点,解答进阶篇的相关问题,同时也会为您带来@ react-navigation / native和@ react-navigation / stack读取整个堆栈、React Native Paper Provider 和 React Navigation NavigationContainer 在 React Native Web 中导致错误、React Native react-navigation 导航使用详解、react native 导航路由组件react-navigation的使用的实用方法。
本文目录一览:- React Native未来导航者:react-navigation 使用详解(进阶篇)(react native 导航器)
- @ react-navigation / native和@ react-navigation / stack读取整个堆栈
- React Native Paper Provider 和 React Navigation NavigationContainer 在 React Native Web 中导致错误
- React Native react-navigation 导航使用详解
- react native 导航路由组件react-navigation的使用
React Native未来导航者:react-navigation 使用详解(进阶篇)(react native 导航器)
刚创建的React Native 微信公众号,欢迎微信扫描关注订阅号,每天定期会分享react native 技术文章,移动技术干货,精彩文章技术推送。同时可以扫描我的微信加入react-native技术交流微信群。欢迎各位大牛,React Native技术爱好者加入交流!
本篇内容为react-navigation的进阶内容以及高级用法。
(1)适配顶部导航栏标题:
测试中发现,在iphone上标题栏的标题为居中状态,而在Android上则是居左对齐。所以需要我们修改源码,进行适配。
【node_modules -- react-navigation -- src -- views -- Header.js】的326行代码处,修改为如下:
title: { bottom: 0,left: TITLE_OFFSET,right: TITLE_OFFSET,top: 0,position: 'absolute',alignItems: 'center',}
上面方法通过修改源码的方式其实略有弊端,毕竟扩展性不好。还有另外一种方式就是,在navigationoptions中设置headerTitleStyle的alignSelf为 ' center '即可解决。
(2)去除返回键文字显示:
【node_modules -- react-navigation -- src -- views -- HeaderBackButton.js】的91行代码处,修改为如下即可。{Platform.OS === 'ios' && title && <Text onLayout={this._onTextLayout} style={[styles.title,{ color: tintColor }]} numberOfLines={1} > {backButtonTitle} </Text>}
将上述代码删除即可。
(3)动态设置头部按钮事件:
当我们在头部设置左右按钮时,肯定避免不了要设置按钮的单击事件,但是此时会有一个问题,navigationoptions是被修饰为static类型的,所以我们在按钮的onPress的方法中不能直接通过this来调用Component中的方法。如何解决呢?在官方文档中,作者给出利用设置params的思想来动态设置头部标题。那么我们可以利用这种方式,将单击回调函数以参数的方式传递到params,然后在navigationoption中利用navigation来取出设置到onPress即可:
componentDidMount () { /** * 将单击回调函数作为参数传递 */ this.props.navigation.setParams({ switch: () => this.switchView() }); }
/** * 切换视图 */ switchView() { alert('切换') }
static navigationoptions = ({navigation,screenProps}) => ({ headerTitle: '企业服务',headerTitleStyle: CommonStyles.headerTitleStyle,headerRight: ( <NavigatorItem icon={ Images.ic_navigator } onPress={ ()=> navigation.state.params.switch() }/> ),headerStyle: CommonStyles.headerStyle });
componentDidMount () { /** * 将单击回调函数作为参数传递 */ this.props.navigation.setParams({ switch: () => this.switchView() }); }
/** * 切换视图 */ switchView() { alert('切换') }
static navigationoptions = ({navigation,headerStyle: CommonStyles.headerStyle });
(4)结合BackHandler处理返回和点击返回键两次退出App效果
点击返回键两次退出App效果的需求屡见不鲜。相信很多人在react-navigation下实现该功能都遇到了很多问题,例如,其他界面不能返回。也就是手机本身返回事件在react-navigation之前拦截了。如何结合react-natigation实现呢?和大家分享两种实现方式:
(1)在注册StackNavigator的界面中,注册BackHandler:
componentwillMount(){ BackHandler.addEventListener('hardwareBackPress',this._onBackAndroid ); } componentUnWillMount(){ BackHandler.addEventListener('hardwareBackPress',this._onBackAndroid); } _onBackAndroid=()=>{ let Now = new Date().getTime(); if(Now - lastBackpressed < 2500) { return false; } lastBackpressed = Now; ToastAndroid.show('再点击一次退出应用',ToastAndroid.SHORT); return true; }
(2)监听react-navigation的Router
/** * 处理安卓返回键 */ const defaultStateAction = AppNavigator.router.getStateForAction; AppNavigator.router.getStateForAction = (action,state) => { if(state && action.type === NavigationActions.BACK && state.routes.length === 1) { if (lastBackpressed + 2000 < Date.Now()) { ToastAndroid.show(Constant.hint_exit,ToastAndroid.SHORT); lastBackpressed = Date.Now(); const routes = [...state.routes]; return { ...state,...state.routes,index: routes.length - 1,}; } } return defaultStateAction(action,state); };
(5)实现Android中界面跳转左右切换动画
react-navigation在Android中默认的界面切换动画是上下。如何实现左右切换呢?很简单的配置即可:
import CardStackStyleInterpolator from 'react-navigation/src/views/CardStackStyleInterpolator';然后在StackNavigator的配置下添加如下代码:
transitionConfig:()=>({ screenInterpolator: CardStackStyleInterpolator.forHorizontal,})
(6)解决快速点击多次跳转
当我们快速点击跳转时,会开启多个重复的界面,如何解决呢。其实在官方git中也有提示,解决这个问题需要修改react-navigation源码:
找到src文件夹中的addNavigationHelpers.js文件,替换为如下文本即可:
export default function<S: *>(navigation: NavigationProp<S,NavigationAction>) { // 添加点击判断 let debounce = true; return { ...navigation,goBack: (key?: ?string): boolean => navigation.dispatch( NavigationActions.back({ key: key === undefined ? navigation.state.key : key,}),),navigate: (routeName: string,params?: NavigationParams,action?: NavigationAction,): boolean => { if (debounce) { debounce = false; navigation.dispatch( NavigationActions.navigate({ routeName,params,action,); setTimeout( () => { debounce = true; },500,); return true; } return false; },/** * For updating current route params. For example the nav bar title and * buttons are based on the route params. * This means `setParams` can be used to update nav bar for example. */ setParams: (params: NavigationParams): boolean => navigation.dispatch( NavigationActions.setParams({ params,key: navigation.state.key,}; }
(7)解决goBack,根据路由名称返回指定界面
react-navigation默认不支持根据路由名返回指定界面,官方只提供了根据Key来做goBack的指定返回。解决这个问题同样需要修改react-navigation源码,在Navigation.goBack条件下添加对路由名的支持。找到/node_modules/react-navigation/src/routers/StackRouter.js,全局搜索backRoute,将条件判断语句替换为如下代码:
if (action.type === NavigationActions.BACK) { const key = action.key; let backRouteIndex = null; if (key) { const backRoute = null; if(key.indexOf('id') >= 0) { backRoute = state.routes.find((route: *) => route.key === action.key); } else { backRoute = state.routes.find(route => route.routeName === action.key); } backRouteIndex = state.routes.indexOf(backRoute); } if (backRouteIndex == null) { return StateUtils.pop(state); } if (backRouteIndex > 0) { return { ...state,routes: state.routes.slice(0,backRouteIndex),index: backRouteIndex - 1,}; } }
(8)自定义Tab
import React,{ Component } from 'react'; import { AppRegistry,Platform,StyleSheet,Text,View,TouchableOpacity,NativeModules,imagebackground,deviceeventemitter } from 'react-native'; export default class Tab extends Component { renderItem = (route,index) => { const { navigation,jumpToIndex,} = this.props; const focused = index === navigation.state.index; const color = focused ? this.props.activeTintColor : this.props.inactiveTintColor; let TabScene = { focused:focused,route:route,tintColor:color }; if(index==1){ return (<View style={[styles.tabItem,{backgroundColor:'transparent'}]}> </View> ); } return ( <TouchableOpacity key={route.key} style={styles.tabItem} onPress={() => jumpToIndex(index)} > <View style={styles.tabItem}> {this.props.renderIcon(TabScene)} <Text style={{ ...styles.tabText,marginTop:SCALE(10),color }}>{this.props.getLabel(TabScene)}</Text> </View> </TouchableOpacity> ); }; render(){ const {navigation,jumpToIndex} = this.props; const {routes,} = navigation.state; const focused = 1 === navigation.state.index; const color = focused ? this.props.activeTintColor : this.props.inactiveTintColor; let TabScene = { focused:focused,route:routes[1],tintColor:color }; return ( <View style={{width:WIDTH}}> <View style={styles.tab}> {routes && routes.map((route,index) => this.renderItem(route,index))} </View> <TouchableOpacity key={"centerView"} style={[styles.tabItem,{position:'absolute',bottom:0,left:(WIDTH-SCALE(100))/2,right:WIDTH-SCALE(100),height:SCALE(120)}]} onPress={() => jumpToIndex(1)} > <View style={styles.tabItem}> {this.props.renderIcon(TabScene)} <Text style={{ ...styles.tabText,color }}>{this.props.getLabel(TabScene)}</Text> </View> </TouchableOpacity> </View> ); } } const styles = { tab:{ width:WIDTH,backgroundColor:'transparent',flexDirection:'row',justifyContent:'space-around',alignItems:'flex-end' },tabItem:{ height:SCALE(80),width:SCALE(100),alignItems:'center',justifyContent:'center' },tabText:{ marginTop:SCALE(13),fontSize:FONT(10),color:Color.C7b7b7b },tabTextChoose:{ color:Color.f3474b },tabImage:{ width:SCALE(42),height:SCALE(42),},}
componentDidMount () { /** * 将单击回调函数作为参数传递 */ this.props.navigation.setParams({ switch: () => this.switchView() }); }
/** * 切换视图 */ switchView() { alert('切换') }
static navigationoptions = ({navigation,headerStyle: CommonStyles.headerStyle });
(9)如何在屏幕控件之外的模块获取当前界面及navigation实例
很多情况下,我们都需要处理登录token失效的情况。例如:在当前设备登录后不退出,此时在另一台设备登录,导致第一个设备用户登录状态失效,此时在第一台设备操作网络请求时,需要提醒用户登录失效,跳转登录界面,并重新登录。
这种需求很常见,关于网络请求我们一般会封装为一个HttpUtil。然后在Component中去调用。此时如果需要处理登录失效的跳转逻辑,需要写在HttpUtil,那么在HttpUtil中就没办法获取navigation来做跳转,那么如何解决呢?下面提供一种方案,很实用:
定义一个Component的基类,包含当前显示的Component实例:screen,以及导航函数。
import React,{Component} from 'react'; export default class Base extends Component { static screen; constructor(props) { super(props); Base.screen = this; } nav() { return this.props.navigation; } }
在其他组件/模块中,我可以调用它来导航到不同的屏幕:
Base.screen.nav().navigate(...);
这样不管在哪个屏幕上,并且可以随时获取导航对象以在需要时重定向用户。
(10)react-navigation高级用法:实现自定义Tab切换效果。
react-navigation 库中提供了实现自定义Router切换的方式,需要用到的组件如下:
Tabrouter,createNavigator,createNavigationContainer
1. Tabrouter用来自定义路由栈
2.createNavigator用来创建导航组件
3.createNavigationContainer作为导航组件的容器组件
自定义Router切换的流程大致如下:
1. 创建StackNavigator
2. 创建Tabrouter
3. 定义导航样式
4. 定义整体路由切换组件
5. 创建Navigator
来看核心代码:
// 界面组件 import FirstPage from './scene/FirstPage'; import SecondPage from './scene/SecondPage'; import ThirdPage from './scene/ThirdPage'; import DetailPage from './scene/DetailPage';
// 引入 react-navigation 核心组件 import { Tabrouter,StackNavigator,addNavigationHelpers,createNavigationContainer,} from 'react-navigation';
// 创建 3个 StackNavigator const FirstScreen = StackNavigator( { First: { screen: FirstPage },Detail: { screen: DetailPage } } ); const SecondScreen = StackNavigator( { Second: { screen: SecondPage } } ); const ThirdScreen = StackNavigator( { Third: { screen: ThirdPage } } );
// 定义 Tabrouter const FirstScene = ({ navigation }) => ( <FirstScreen /> ); const SecondScene = ({ navigation }) => ( <SecondScreen /> ); const ThirdScene = ({ navigation }) => ( <ThirdScreen /> ); const CustomTabrouter = Tabrouter( { First: { screen: FirstScene,path: 'firstScene' },Second: { screen: SecondScene,path: 'secondScene' },Third: { screen: ThirdScene,path: 'thirdScene' },{ initialRouteName: 'First' } );
// 定义TabBar const CustomTabBar = ({ navigation,activeRouteName }) => { const { routes } = navigation.state; return ( <View style={ styles.tabContainer }> <ScrollView> { routes.map((route,index)=>( <TouchableOpacity key={ index } onPress={() => navigation.navigate(route.routeName)}> <Text style={[ styles.tabbarText,activeRouteName === route.routeName ? styles.active : styles.inactive ]}> { route.routeName } </Text> </TouchableOpacity> )) } </ScrollView> </View> ) }
// 定义TabView const CustomTabView = ({ router,navigation }) => { const { routes,index } = navigation.state; const activeRouteName = routes[index].routeName; const ActiveScreen = router.getComponentForRouteName(activeRouteName); return( <View style={ styles.container }> <CustomTabBar navigation={ navigation } activeRouteName={ activeRouteName } /> <ActiveScreen navigation={ addNavigationHelpers( { dispath: navigation.dispatch,state: routes[index] } ) } /> </View> ) }
// 创建Navigator const CustomTabs = createNavigationContainer( createNavigator(CustomTabrouter)(CustomTabView) ) export default CustomTabs;
// Style 样式 const styles = StyleSheet.create({ tabContainer: { width: 86,zIndex: 888,flexDirection:'column',justifyContent:'center',backgroundColor: '#e7e7e7',borderRightWidth:1,borderColor: '#e0e0e0' },tabbarText: { fontSize: 18,fontWeight: 'bold',marginTop: 20,marginBottom: 20,color: 'black' },active: { color: 'red',inactive: { color: 'black',container: { flexDirection:'row',flex: 1,} });通过上述代码,我们就可以创建出类似于饿了么App中商品分类的模块切换效果。
(11)定义某个界面的切换动画效果
有时候产品会存在某个界面的切换动画和其他不同,那么如何实现呢?很简单,只需要在StackNavigator中配置参数下声明以下代码:
transitionConfig:()=>({ screenInterpolator: (props)=> { const { scene } = props if (scene.route.routeName === 'VIPDetailPage') { return CardStackStyleInterpolator.forFade } else { return CardStackStyleInterpolator.forHorizontal(props) } } })
效果图
自定义Tabrouter:
@ react-navigation / native和@ react-navigation / stack读取整个堆栈
您可以使用如下所示的useNavigationState钩子来获取当前状态
https://reactnavigation.org/docs/use-navigation-state/
import {useNavigationState} from '@react-navigation/native';
const state = useNavigationState((state) => state);
alert(JSON.stringify(state.routes));
这将在路线中显示屏幕
React Native Paper Provider 和 React Navigation NavigationContainer 在 React Native Web 中导致错误
如何解决React Native Paper Provider 和 React Navigation NavigationContainer 在 React Native Web 中导致错误?
我是 React-native 和 React-native-web 的初学者。我目前正在处理一个使用 React-Native-paper
和 @react-navigation/native
库的现有项目。我正在尝试使用现有代码/项目作为 Web 应用程序运行。但是当我在 App.js 中使用以下代码时,我在运行 Web 应用程序的控制台中收到一个错误:
import React from ''react'';
import {Provider} from ''react-native-paper'';
import {NavigationContainer} from ''@react-navigation/native'';
export const App = props => {
return (
<NavigationContainer>
<Provider>
<Navigator />
</Provider>
</NavigationContainer>
);
};
我得到的错误是:
Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
at AppContainer (webpack://web_tester/./node_modules/react-native-web/dist/exports/AppRegistry/AppContainer.js?:22:24)
react-dom.development.js:14906 Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This Could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
at Object.throwInvalidHookError (VM231 react-dom.development.js:14906)
at Object.useContext (VM227 react.development.js:1504)
at eval (VM252 index.js:83)
at renderWithHooks (VM231 react-dom.development.js:14985)
at updateForwardRef (VM231 react-dom.development.js:17044)
at beginWork (VM231 react-dom.development.js:19098)
at HTMLUnkNownElement.callCallback (VM231 react-dom.development.js:3945)
at Object.invokeGuardedCallbackDev (VM231 react-dom.development.js:3994)
at invokeGuardedCallback (VM231 react-dom.development.js:4056)
at beginWork$1 (VM231 react-dom.development.js:23959)
我创建了一个包含错误的简单 git repository。请看一下。
任何其他方面的见解都会有所帮助。并提前致谢。
解决方法
尝试将 react-native-paper 提供程序放在外面。我的应用使用以下代码使用 react-native 和 react-native-web 工作正常。
我已经通过 Expo which is the recommended way 设置了 react-native-web:引用自 react-native-web 文档:“通常建议您使用 Expo。”
<PaperProvider theme={theme} settings={settings}>
<NavigationContainer>
<RootStackScreens />
</NavigationContainer>
</PaperProvider>
React Native react-navigation 导航使用详解
一、开源库介绍
今年1月份,新开源的react-natvigation库备受瞩目。在短短不到3个月的时间,github上星数已达4000+。Fb推荐使用库,并且在React Native当前最新版本0.44中将Navigator删除。react-navigation据称有原生般的性能体验效果。可能会成为未来React Native导航组件的主流军。本篇内容基于【 ^1.0.0-beta.9 】版本来介绍关于该库的使用和实战技巧。可以看到,虽然是beta版本,不过基本稳定,大家可放心在项目中使用。奉上 react-navigation 官方文档
该库包含三类组件:
(1)StackNavigator:用来跳转页面和传递参数 (2)TabNavigator:类似底部导航栏,用来在同一屏幕下切换不同界面 (3)DrawerNavigator:侧滑菜单导航栏,用于轻松设置带抽屉导航的屏幕二、react-navigation使用
具体内容大致分为如下:
(1)react-navigation库属性介绍 (2)StackNavigator、TabNavigator实现界面间跳转,Tab切换 (3)StackNavigator界面间跳转、传值、取值 (4)DrawerNavigator实现抽屉导航菜单 (5)DrawerNavigator扩展功能 (6)自定义react-navigation1、StackNavigator属性介绍
navigationoptions:配置StackNavigator的一些属性。- title:标题,如果设置了这个导航栏和标签栏的title就会变成一样的,不推荐使用
- header:可以设置一些导航的属性,如果隐藏顶部导航栏只要将这个属性设置为null
- headerTitle:设置导航栏标题,推荐
- headerBackTitle:设置跳转页面左侧返回箭头后面的文字,默认是上一个页面的标题。可以自定义,也可以设置为null
- headerTruncatedBackTitle:设置当上个页面标题不符合返回箭头后的文字时,默认改成"返回"
- headerRight:设置导航条右侧。可以是按钮或者其他视图控件
- headerLeft:设置导航条左侧。可以是按钮或者其他视图控件
- headerStyle:设置导航条的样式。背景色,宽高等
- headerTitleStyle:设置导航栏文字样式
- headerBackTitleStyle:设置导航栏‘返回'文字样式
- headerTintColor:设置导航栏颜色
- headerPressColorAndroid:安卓独有的设置颜色纹理,需要安卓版本大于5.0
- gesturesEnabled:是否支持滑动返回手势,iOS默认支持,安卓默认关闭
screen:对应界面名称,需要填入import之后的页面
mode:定义跳转风格
card:使用iOS和安卓默认的风格
modal:iOS独有的使屏幕从底部画出。类似iOS的present效果
headerMode:返回上级页面时动画效果
float:iOS默认的效果
screen:滑动过程中,整个页面都会返回
none:无动画
cardStyle:自定义设置跳转效果
- transitionConfig: 自定义设置滑动返回的配置
- onTransitionStart:当转换动画即将开始时被调用的功能
- ontransitionend:当转换动画完成,将被调用的功能
path:路由中设置的路径的覆盖映射配置
initialRouteName:设置默认的页面组件,必须是上面已注册的页面组件
initialRouteParams:初始路由参数
注:大家可能对于path不太理解。path属性适用于其他app或浏览器使用url打开本app并进入指定页面。path属性用于声明一个界面路径,例如:【/pages/Home】。此时我们可以在手机浏览器中输入:app名称://pages/Home来启动该App,并进入Home界面。
2、TabNavigator属性介绍
screen:和导航的功能是一样的,对应界面名称,可以在其他页面通过这个screen传值和跳转。
navigationoptions:配置TabNavigator的一些属性
title:标题,会同时设置导航条和标签栏的title
tabBarVisible:是否隐藏标签栏。默认不隐藏(true)
tabBarIcon:设置标签栏的图标。需要给每个都设置
tabBarLabel:设置标签栏的title。推荐
导航栏配置
tabBarPosition:设置tabbar的位置,iOS默认在底部,安卓默认在顶部。(属性值:'top','bottom')
swipeEnabled:是否允许在标签之间进行滑动
animationEnabled:是否在更改标签时显示动画
lazy:是否根据需要懒惰呈现标签,而不是提前,意思是在app打开的时候将底部标签栏全部加载,默认false,推荐为true
trueinitialRouteName: 设置默认的页面组件
backBehavior:按 back 键是否跳转到第一个Tab(首页), none 为不跳转
tabBarOptions:配置标签栏的一些属性iOS属性
activeTintColor:label和icon的前景色 活跃状态下
activeBackgroundColor:label和icon的背景色 活跃状态下
inactiveTintColor:label和icon的前景色 不活跃状态下
inactiveBackgroundColor:label和icon的背景色 不活跃状态下
showLabel:是否显示label,默认开启 style:tabbar的样式
labelStyle:label的样式安卓属性
activeTintColor:label和icon的前景色 活跃状态下
inactiveTintColor:label和icon的前景色 不活跃状态下
showIcon:是否显示图标,默认关闭
showLabel:是否显示label,默认开启 style:tabbar的样式
labelStyle:label的样式 upperCaseLabel:是否使标签大写,默认为true
pressColor:material涟漪效果的颜色(安卓版本需要大于5.0)
pressOpacity:按压标签的透明度变化(安卓版本需要小于5.0)
scrollEnabled:是否启用可滚动选项卡 tabStyle:tab的样式
indicatorStyle:标签指示器的样式对象(选项卡底部的行)。安卓底部会多出一条线,可以将height设置为0来暂时解决这个问题
labelStyle:label的样式
iconStyle:图标样式
3、DrawerNavigator属性介绍
DrawerNavigatorConfig
- drawerWidth - 抽屉的宽度
- drawerPosition - 选项是左或右。 默认为左侧位置
- contentComponent - 用于呈现抽屉内容的组件,例如导航项。 接收抽屉的导航。 默认为DrawerItems
- contentOptions - 配置抽屉内容
initialRouteName - 初始路由的routeName
order - 定义抽屉项目顺序的routeNames数组。
路径 - 提供routeName到路径配置的映射,它覆盖routeConfigs中设置的路径。
backBehavior - 后退按钮是否会切换到初始路由? 如果是,设置为initialRoute,否则为none。 默认为initialRoute行为
DrawerItems的contentOptions属性
- activeTintColor - 活动标签的标签和图标颜色
- activeBackgroundColor - 活动标签的背景颜色
- inactiveTintColor - 非活动标签的标签和图标颜色
- inactiveBackgroundColor - 非活动标签的背景颜色
内容部分的样式样式对象
labelStyle - 当您的标签是字符串时,要覆盖内容部分中的文本样式的样式对象 从上述中大致了解了react-navigation三种组件的一些基本属性,所以到我们甩起袖子撸代码见证下奇迹了。
4、使用StackNavigator + TabNavigator实现Tab界面切换、界面间导航
API定义:StackNavigator(RouteConfigs,StackNavigatorConfig)、TabNavigator(RouteConfigs,TabNavigatorConfig)
(1)集成 react-navigation:在终端执行 【 npm install react-navigation --save 】
(2)界面中导入必要组件:
(3)定义TabNavigator:
}
);
TabBarItem为封装的组件:
export default class TabBarItem extends Component {
render() {
return(
<Image source={ this.props.focused ? this.props.selectedImage : this.props.normalImage }
style={ { tintColor:this.props.tintColor,width:25,height:25 } }
/>
)
}
}
可以看到,我们定义了一个名称为【Tab】的TabNavigator的导航组件。在组件中,分为两层参数:
(1)第一层参数定义了要切换的界面,即【首页】、【我】两个界面组件,通过screen属性指定。并且通过navigationoptions属性设置相关属性参数。
(2)设置导航栏的属性参数。
TabNavigator定义好之后,需要用StackNavigator,顾名思义,StackNavigator就是以栈的方式来存放整个界面的,而
TabNavigator是作为一个界面内不同子界面之间切换。所以还需要我们定义StackNavigator:
{
Tab:{screen:Tab},Product:{screen:ProductScreen}
},{
navigationoptions:{
headerBackTitle:null,headerTintColor:'#333333',showIcon:true,mode:'card',});
看起来和TabNavigator很相似,同样是指定了两个参数:
(1)指定要跳转的界面组件。同样是screen属性标识界面组件,不多赘述。
(2)定义跳转属性参数,即顶部导航栏的一些参数设置和跳转方式。
可以看到,我们将Tab作为一个界面设置到了StackNavigator。这样就可以实现Tab导航和界面间跳转的效果了。
最后就是在render中引用StackNavigator:
render() {
return (
StackNavigator还提供了onNavigationStateChange回调方法,用来监听导航状态的改变。具体不再赘述。实现了界面跳转和切换,那么就该来增加下界面之间的感情了,来看看如何实现界面之间的传值和取值。
5、界面间跳转、传值、取值
在界面组件注入到StackNavigator中时,界面组件就被赋予了navigation属性,即在界面组件中可以通过【this.props.navigation】获取并进行一些操作。
navigation属性中提供了很多的函数简化界面间操作,简单列举几点:
(1)通过navigate函数实现界面之间跳转:
参数为我们在StackNavigator注册界面组件时的名称。同样也可以从当前页面返回到上一页:
(2)跳转时传值:
第一个参数同样为要跳转的界面组件名称,第二个参数为要传递的参数,info可以理解为key,后面即传递的参数。
(3)获取值:
通过state.params来获取传来的参数,后面为key值。此处为info。
以上实现完成,我们就可以愉快的玩耍啦~~ 什么?忽然发现在Android上的效果和IOS效果不一样。老板要界面一致哇~ 怎么办?那就需要我们进行简单的适配了。
三、DrawerNavigator实现抽屉导航
1、导航实现
API定义:DrawerNavigator(RouteConfigs,DrawerNavigatorConfig)
(1)界面中定义DrawerNavigator:
export default class Demo extends Component {
render() {
return (
const Navigator = DrawerNavigator({
Home:{screen:HomeScreen},mine:{screen:mineScreen},});
const styles = StyleSheet.create({
container: {
flex: 1,});
AppRegistry.registerComponent('Demo',() => Demo);
定义方式和StackNavigator基本类似,不再赘述。
(2)HomeScreen界面和mineScreen界面:
drawerLabel: '首页',drawerIcon:({tintColor}) => (
<Image
source={require('./../imgs/ic_happy.png')}
style={[styles.icon,{tintColor: tintColor}]}/>
),};
render() {
return(
_skip() {
this.props.navigation.navigate("mine");
}
}
export default class minePage extends Component {
static navigationoptions = {
drawerLabel:'我',drawerIcon: ({ tintColor }) => (
<Image
source={require('./../imgs/ic_h.png')}
style={[styles.icon,{tintColor: tintColor}]}
/>
),};
render() {
return(
/**
- 跳转
*/
_skip() {
this.props.navigation.goBack();
}
}
代码很简单,实现了界面之间的跳转。
2、扩展功能
(1)默认DrawerView不可滚动。要实现可滚动视图,必须使用contentComponent自定义容器,如下所示:
(2)可以覆盖导航使用的默认组件,使用DrawerItems自定义导航组件:
const CustomDrawerContentComponent = (props) => (
(3)嵌套抽屉导航
如果您嵌套DrawerNavigation,抽屉将显示在父导航下方。
四、自定义react-navigation
(1)适配顶部导航栏标题:
测试中发现,在iphone上标题栏的标题为居中状态,而在Android上则是居左对齐。所以需要我们修改源码,进行适配。 【node_modules -- react-navigation -- src -- views -- Header.js】的326行代码处,修改为如下:
上面方法通过修改源码的方式其实略有弊端,毕竟扩展性不好。还有另外一种方式就是,在navigationoptions中设置headerTitleStyle的alignSelf为 ' center '即可解决。
(2)去除返回键文字显示:
【node_modules -- react-navigation -- src -- views -- HeaderBackButton.js】的91行代码处,修改为如下即可。
将上述代码删除即可。
(3)动态设置头部按钮事件:
当我们在头部设置左右按钮时,肯定避免不了要设置按钮的单击事件,但是此时会有一个问题,navigationoptions是被修饰为static类型的,所以我们在按钮的onPress的方法中不能直接通过this来调用Component中的方法。如何解决呢?在官方文档中,作者给出利用设置params的思想来动态设置头部标题。那么我们可以利用这种方式,将单击回调函数以参数的方式传递到params,然后在navigationoption中利用navigation来取出设置到onPress即可:
(4)结合BackHandler处理返回和点击返回键两次退出App效果
点击返回键两次退出App效果的需求屡见不鲜。相信很多人在react-navigation下实现该功能都遇到了很多问题,例如,其他界面不能返回。也就是手机本身返回事件在react-navigation之前拦截了。如何结合react-natigation实现呢?和大家分享两种实现方式:
(1)在注册StackNavigator的界面中,注册BackHandler:
BackHandler.addEventListener('hardwareBackPress',this._onBackAndroid);
}
_onBackAndroid=()=>{
let Now = new Date().getTime();
if(Now - lastBackpressed < 2500) {
return false;
}
lastBackpressed = Now;
ToastAndroid.show('再点击一次退出应用',ToastAndroid.SHORT);
return true;
}
(2)监听react-navigation的Router
(5)实现Android中界面跳转左右切换动画
react-navigation在Android中默认的界面切换动画是上下。如何实现左右切换呢?很简单的配置即可:
然后在StackNavigator的配置下添加如下代码:
(6)解决快速点击多次跳转
当我们快速点击跳转时,会开启多个重复的界面,如何解决呢。其实在官方git中也有提示,解决这个问题需要修改react-navigation源码:
找到scr文件夹中的addNavigationHelpers.js文件,替换为如下文本即可:
五、效果图
抽屉导航:
以上就是我们实战中常用的属性和技巧。具体的操作还需要大家在实践过程中测试体会。希望对大家的学习有所帮助,也希望大家多多支持小编。
总结
以上是小编为你收集整理的React Native react-navigation 导航使用详解全部内容。
如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。
react native 导航路由组件react-navigation的使用
navigation的几个难点和问题:
1.底部tab是否可以加上中间的大按钮? 如果加上,如何触发事件? js文件放哪?
2.navigation的登录注册页面。成功后应该不能返回刚刚的登录页面?清空页面栈?
3.登录成功跳转到大厅?意图页面?还是当前所在页?弹出model是不是可以解决所有问题?登录成功如何重刷当前页?
一、前言
在 React Native
中,官方已经推荐使用 react-navigation
来实现各个界面的跳转和不同板块的切换。 react-navigation
主要包括三个组件:
TabNavigator
切换组件 ,用来实现同一个页面上不同界面的切换,即tab选项卡StackNavigator
导航组件,用于实现各个页面之间的跳转,即页面跳转(通过stack栈记录)DrawerNavigator
抽屉组件,可以实现侧滑的抽屉效果
本次我们主要说说前两个,DrawerNavigator
笔者不曾使用
(一)、怎么使用navigation(入口和概览)
export default class Navigator extends Component {
render() {
return(
<Navigator />
)
}
}
const Navigator = StackNavigator(StackRouteConfigs, StackNavigatorConfigs)
上面的StackNavigator就是react-navigation
的导航组件:
StackNavigator
导航组件,用于实现各个页面之间的跳转,即页面跳转(通过stack栈记录)
那么它的两个参数 StackNavigator(StackRouteConfigs, StackNavigatorConfigs) 又是干啥的呢?
(二)、怎么使用StackNavigator
const StackRouteConfigs = {
MainTab: {
screen: MainTab,
navigationOptions: ({navigation}) => ({
//主页大厅的tab及其相关页面
}),
},
Datail: {
screen: DatailPage,
navigationOptions: ({navigation}) => ({
}),
},
};
const StackNavigatorConfig = {
initialRouteName: ''MainTab'', //默认先加载的页面
navigationOptions: { //路由页面的配置选项,可定义头部内容、样式
},
mode: ''card'', //页面跳转方式,card 表示原生系统默认的方式和 modal只针对iOS平台,模态跳转
headerMode: ''screen'',页面跳转时,头部的动画模式,有 float 、 screen 、 none 三种
};
StackRouteConfigs参数表示各个页面路由配置,类似于android原生开发中的 AndroidManifest.xml
,它是让导航器知道需要导航的路由对应的页面。
StackNavigatorConfigs参数表示导航器的配置,包括导航器的初始页面、各个页面之间导航的动画、页面的配置选项等等:


initialRouteName - 导航器组件中初始显示页面的路由名称,如果不设置,则默认第一个路由页面为初始显示页面
initialRouteParams - 给初始路由的参数,在初始显示的页面中可以通过 this.props.navigation.state.params 来获取
navigationOptions - 路由页面的配置选项,它会被 RouteConfigs 参数中的 navigationOptions 的对应属性覆盖。
paths - 路由中设置的路径的覆盖映射配置
mode - 页面跳转方式,有 card 和 modal 两种,默认为 card :
card - 原生系统默认的的跳转
modal - 只针对iOS平台,模态跳转
headerMode - 页面跳转时,头部的动画模式,有 float 、 screen 、 none 三种:
float - 渐变,类似iOS的原生效果
screen - 标题与屏幕一起淡入淡出
none - 没有动画
cardStyle - 为各个页面设置统一的样式,比如背景色,字体大小等
transitionConfig - 配置页面跳转的动画,覆盖默认的动画效果
onTransitionStart - 页面跳转动画即将开始时调用
onTransitionEnd - 页面跳转动画一旦完成会马上调用
上面的MainTab表示大厅内的Tab内容
也就是:
TabNavigator
切换组件 ,用来实现同一个页面上不同界面的切换,即tab选项卡
它怎么使用呢???
(三)、怎么使用TabNavigator
const MainTab = TabNavigator(TabRouteConfigs, TabNavigatorConfigs);
const TabNavigatorConfigs = {
initialRouteName: ''Recommend'',
tabBarComponent: TabBarBottom,
tabBarPosition: ''bottom'',
lazy: true,
tabBarOptions: {
activeTintColor: ''red'',
inactiveTintColor: ''#999'',
showIcon: true,
indicatorStyle: {height: 0},
style: {
backgroundColor: ''#fff'',
height: (height*0.08 < 65) ? 65 : height*0.08,
paddingVertical: (height*0.08 < 65) ? 5 : height*0.08/13,
},
labelStyle: {fontSize: 11},
}
};
const TabRouteConfigs = {
Attention: {
screen: AttentionScreen,
navigationOptions: ({navigation}) => ({
tabBarLabel: ''关注'',
tabBarIcon: ({focused, tintColor}) => (
<Image source={focused ? LocalImage.AttentionSelectedImage : LocalImage.AttentionImage} style={{width: ''33%''}} resizeMode=''contain''> </Image>
),
}),
},
Recommend: {
screen: RecommendScreen,
navigationOptions: ({navigation}) => ({
tabBarLabel: ''推荐'',
tabBarIcon: ({focused, tintColor}) => (
<Image source={focused ? LocalImage.RecommendSelectedImage : LocalImage.RecommendImage} style={{width: ''33%''}} resizeMode=''contain''> </Image>
),
}),
},
Library: {
screen: LibraryScreen,
navigationOptions: ({navigation}) => ({
tabBarLabel: ''仓库'',
tabBarIcon: ({focused, tintColor}) => (
<Image source={focused ? LocalImage.LibrarySelectedImage : LocalImage.LibraryImage} style={{width: ''33%''}} resizeMode=''contain''> </Image>
),
}),
},
Profile: {
screen: ProfileScreen,
navigationOptions: ({navigation}) => ({
tabBarLabel: ''我的'',
tabBarIcon: ({focused, tintColor}) => (
<Image source={focused ? LocalImage.ProfileSelectedImage : LocalImage.ProfileImage} style={{width: ''33%''}} resizeMode=''contain''> </Image>
),
}),
},
};
TabNavigator
切换组件 TabNavigatorConfigs 的配置


tabBarComponent - Tab选项卡组件,有 TabBarBottom 和 TabBarTop 两个值,在iOS中默认为 TabBarBottom ,在Android中默认为 TabBarTop 。
TabBarTop - 在页面的顶部
TabBarBottom - 在页面的底部
tabBarPosition - Tab选项卡的位置,有 top 或 bottom 两个值
swipeEnabled - 是否可以滑动切换Tab选项卡
animationEnabled - 点击Tab选项卡切换界面是否需要动画
lazy - 是否懒加载页面
initialRouteName - 初始显示的Tab对应的页面路由名称
order - 用路由名称数组来表示Tab选项卡的顺序,默认为路由配置顺序
paths - 路径配置
backBehavior - androd点击返回键时的处理,有 initialRoute 和 none 两个值
initailRoute - 返回初始界面
none - 退出
tabBarOptions - Tab配置属性,用在 TabBarTop 和 TabBarBottom 时有些属性不一致:
用于 TabBarTop 时:
activeTintColor - 选中的文字颜色
inactiveTintColor - 未选中的文字颜色
showIcon - 是否显示图标,默认显示
showLabel - 是否显示标签,默认显示
upperCaseLabel - 是否使用大写字母,默认使用
pressColor - android 5.0以上的MD风格波纹颜色
pressOpacity - android 5.0以下或者iOS按下的透明度
scrollEnabled - 是否可以滚动
tabStyle - 单个Tab的样式
indicatorStyle - 指示器的样式
labelStyle - 标签的样式
iconStyle - icon的样式
style - 整个TabBar的样式
用于 TabBarBottom 时:
activeTintColor - 选中Tab的文字颜色
activeBackgroundColor - 选中Tab的背景颜色
inactiveTintColor - 未选中Tab的的文字颜色
inactiveBackgroundColor - 未选中Tab的背景颜色
showLabel - 是否显示标题,默认显示
style - 整个TabBar的样式
labelStyle - 标签的样式
tabStyle - 单个Tab的样式
三、结语
暂时就这样
我们今天的关于React Native未来导航者:react-navigation 使用详解和进阶篇的分享已经告一段落,感谢您的关注,如果您想了解更多关于@ react-navigation / native和@ react-navigation / stack读取整个堆栈、React Native Paper Provider 和 React Navigation NavigationContainer 在 React Native Web 中导致错误、React Native react-navigation 导航使用详解、react native 导航路由组件react-navigation的使用的相关信息,请在本站查询。
本文标签: