底部动态导航的实现:
本文将介绍使用react-navigation实现动态导航及动态主题的方法,实现的效果如下,可以动态的更改导航的数量,颜色、图标等,也可以通过后端接收的数据进行动态的修改。核心思路就是通过服务端下发的数组来组成导航器然后把导航器作为一个component吧这个数组给导航器。
DynamicTabNavigator.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
/* 动态导航的配置 */ import React from 'react'; import PopularPage from '../page/PopularPage'; import MaterialIcons from 'react-native-vector-icons/MaterialIcons'; import TrendingPage from '../page/TrendingPage'; import Ionicons from 'react-native-vector-icons/Ionicons'; import FavoritePage from '../page/FavoritePage'; import MyPage from '../page/MyPage'; import Entypo from 'react-native-vector-icons/Entypo'; import {createAppContainer} from 'react-navigation'; import {createBottomTabNavigator, BottomTabBar} from 'react-navigation-tabs'; // 在这里配置页面的默认底部导航 const TABS = { PopularPage:{ screen: PopularPage, navigationOptions:{ tabBarLabel:'最热', tabBarIcon:({tintColor, focused}) => ( <MaterialIcons name={'whatshot'} size={26} style={{color: tintColor}} /> ), }, }, TrendingPage:{ screen: TrendingPage, navigationOptions:{ tabBarLabel:'趋势', tabBarIcon:({tintColor, focused}) => ( <Ionicons name={'md-trending-up'} size={26} style={{color: tintColor}} /> ), }, }, FavoritePage:{ screen: FavoritePage, navigationOptions:{ tabBarLabel:'收藏', tabBarIcon:({tintColor, focused}) => ( <MaterialIcons name={'favorite'} size={26} style={{color: tintColor}} /> ), }, }, MyPage:{ screen: MyPage, navigationOptions:{ tabBarLabel:'我的', tabBarIcon:({tintColor, focused}) => ( <Entypo name={'user'} size={26} style={{color: tintColor}} /> ), }, }, }; export default class DynamicTabNavigation extends React.Component{ constructor(props) { super(props); console.disableYellowBox = true; // 开发环境中禁止弹出黄色的提示框 } // 动态的修改TAB的属性 如tab名等 // 如果要从后端接收就可以在这里地方进行处理 _tabNavigator () { const { PopularPage, TrendingPage, FavoritePage, MyPage} = TABS; const tabs = {PopularPage, TrendingPage, FavoritePage, MyPage}; PopularPage.navigationOptions.tabBarLabel = '最热1'; // 动态修改TAB的属性 return createAppContainer(createBottomTabNavigator( tabs, { tabBarComponent: TabBarComponent, } )); } render(){ const Tab = this._tabNavigator(); return <Tab/>; } } class TabBarComponent extends React.Component{ constructor(props) { super(props); this.theme = { tintColor: props.activeTintColor, updateTime:new Date().getTime(), }; } render(){ const {routes, index} = this.props.navigation.state; if (routes[index].params){ const {theme} = routes[index].params; // 以最新的更新时间为主,防止其他的tab之前的修改覆盖掉 if ( theme && theme.updateTime > this.theme.updateTime){ this.theme = theme; } } return <BottomTabBar {...this.props} activeTintColor = {this.theme.tintColor || this.props.activeTintColor} />; } } |
这段代码首先将默认的react-navigation底部菜单单独拿到一个对象中,然后通过从后端接收的数据(在改代码中没有实现后端的接收部分,在注释处接收)后,对这个对象进行修改,然后在把导航通过这个修改后的对象创建出来返回即可,这里我们还创建了一个this.theme,也可以通过修改this.theme的属性来进行修改。代码中需要注意的是更新时间的问题,这样更加的严谨。
然后在其他页面中调用修改navigation中theme的这个属性即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
render(){ const {navigation} = this.props; return ( <View style={styles.container}> <Text style={styles.welcome}>TrendingPage</Text> <Button title={'change theme to blue'} onPress={ () => navigation.setParams({ theme: { tintColor: 'blue', updateTime: new Date().getTime(), }, }) } /> </View> ); } |
顶部动态导航的实现
顶部导航动态的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
import React, {Component} from 'react'; import {View, Text, StyleSheet} from 'react-native'; import {createMaterialTopTabNavigator} from 'react-navigation-tabs'; import {createAppContainer} from 'react-navigation'; export default class PopularPage extends Component{ constructor(props) { super(props); this.tabNames = ['Java', 'Android', 'iOS', 'React', 'React Navigation', 'PHP']; } _genTabs(){ const tabs = {}; this.tabNames.forEach((item, index)=>{ tabs[`tab${index}`] = { screen: props => <PopularTab {...this.props} tabLabel={item}/>, // 设置顶部导航器的重点 navigationOptions: { title: item, }, }; }); return tabs; } render(){ const TabNavigator = createAppContainer(createMaterialTopTabNavigator( this._genTabs(), { tabBarOptions:{ tabStyle: styles.tabStyle, upperCaseLabel: false, scrollEnabled: true, style: { backgroundColor: '#a67', }, indicatorStyle: styles.indicatorStyle, labelStyle: styles.labelStyle, }, } )); return ( <View style={styles.container}> <TabNavigator/> </View> ); } } // 选项卡组件 class PopularTab extends Component{ render() { return ( <View style={styles.container}> <Text>PopularTab</Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, marginTop: 30, }, welcome:{ fontSize: 20, textAlign: 'center', margin: 10, }, tabStyle:{ minWidth: 50, }, indicatorStyle: { height:2, backgroundColor: 'white', }, labelStyle: { fontSize: 13, marginTop: 6, marginBottom: 6, }, }); |
注意这一段核心代码,通常screen返回的是一个组件名,这里是一组组件然后通过props将动态的组件属性传入进这个组件从而实现动态的显示:
1 2 3 |
tabs[`tab${index}`] = { screen: props => <PopularTab {...this.props} tabLabel={item}/>, // 设置顶部导航器的重点 } |
解决导航的冲突问题
由于用到了两个导航一个是底部导航一个是顶部导航,因此跳转的时候会出现冲突,为了解决这个问题,我们创建一个NavigationUtil的导航工具类,然后把navigation统一的在这个类中进行接管来做一个通用的页面跳转而不是由两个导航自身来跳转以此来解决两个导航同时存在时候的冲突的问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
export default class NavigationUtil { /** * 跳转到指定的页面 * @param params 要传递的参数 * @param page 要跳转的页面名(页面路由) */ static goPage(params, page){ const navigation = NavigationUtil.navigation; if (!navigation){ console.log('NavigationUtil.navigation cannot be null'); } navigation.navigate( page, { ...params, } ); } // 重置到首页 static resetToHomePage(params){ const {navigation} = params; navigation.navigate('Main'); } } |
然后条用上面这个方法进行跳转
1 2 3 4 5 6 7 8 9 10 11 12 |
render() { return ( <View style={styles.container}> <Text>PopularTab</Text> <Text onPress={ ()=>{ NavigationUtil.goPage({}, 'DetailPage') } }>跳转到详情页</Text> </View> ); } |
结合上一篇文章,到目前为止这个APP的主路由结构:(可以看到detailPage的位置)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import {createAppContainer, createSwitchNavigator} from 'react-navigation'; import {createStackNavigator} from 'react-navigation-stack'; import WelcomPage from '../page/WelcomPage'; import HomePage from '../page/HomePage'; import DetailPage from '../page/DetailPage'; // 导航分为两个部分 一部分是欢迎页及之前的导航 一部分是欢迎页之后的导航 // 欢迎页之前的导航 const InitNavigator = createStackNavigator( { WelcomePage:{ screen:WelcomPage, navigationOptions:{ headerShown: false, // 隐藏头部 }, }, } ); //欢迎页之后的导航 const MainNavigator = createStackNavigator({ HomePage:{ screen:HomePage, navigationOptions:{ headerShown: false, }, }, DetailPage:{ screen: DetailPage, navigationOptions:{ // headerShown: false, }, }, }); export default createAppContainer(createSwitchNavigator({ Init: InitNavigator, Main: MainNavigator, },{ navigationOptions:{ headerShown:false, }, } )); |