React Native —— react-navigation的使用

React Native中,官方已经推荐使用react-navigation来实现各个界面的跳转和不同板块的切换。react-navigation主要包括三个组件:

  • StackNavigator 导航组件
  • TabNavigator 切换组件
  • DrawerNavigator 抽屉组件

StackNavigator用于实现各个页面之间的跳转,TabNavigator用来实现同一个页面上不同界面的切换,DrawerNavigator 可以实现侧滑的抽屉效果。

StackNavigator

StackNavigator组件采用堆栈式的页面导航来实现各个界面跳转。它的构造函数:

StackNavigator(RouteConfigs, StackNavigatorConfig)

RouteConfigsStackNavigatorConfig两个参数。

RouteConfigs

RouteConfigs 参数表示各个页面路由配置,类似于android原生开发中的AndroidManifest.xml,它是让导航器知道需要导航的路由对应的页面。

const RouteConfigs = {
    Home: {
        screen: HomePage,
        navigationOptions: ({navigation}) => ({
            title: '首页',
        }),
    },
    Find: {
        screen: FindPage,
        navigationOptions: ({navigation}) => ({
            title: '发现',
        }),
    },
    Mine: {
        screen: MinePage,
        navigationOptions: ({navigation}) => ({
            title: '我的',
        }),
    },
};

这里给导航器配置了三个页面,HomeFindMine为路由名称,screen属性值HomePageFindPageMinePage为对应路由的页面。

navigationOptions为对应路由页面的配置选项:

  • title - 可以作为头部标题headerTitle,或者Tab标题tabBarLabel
  • header - 自定义的头部组件,使用该属性后系统的头部组件会消失
  • headerTitle - 头部的标题,即页面的标题
  • headerBackTitle - 返回标题,默认为title
  • headerTruncatedBackTitle - 返回标题不能显示时(比如返回标题太长了)显示此标题,默认为“Back”
  • headerRight - 头部右边组件
  • headerLeft - 头部左边组件
  • headerStyle - 头部组件的样式
  • headerTitleStyle - 头部标题的样式
  • headerBackTitleStyle - 头部返回标题的样式
  • headerTintColor - 头部颜色
  • headerPressColorAndroid - Android 5.0以上MD风格的波纹颜色
  • gesturesEnabled - 否能侧滑返回,iOS默认trueAndroid默认false
StackNavigatorConfig

StackNavigatorConfig参数表示导航器的配置,包括导航器的初始页面、各个页面之间导航的动画、页面的配置选项等等:

const StackNavigatorConfig = {
    initialRouteName: 'Home',
    initialRouteParams: {initPara: '初始页面参数'},
    navigationOptions: {
        title: '标题',
        headerTitleStyle: {fontSize: 18, color: '#666666'},
        headerStyle: {height: 48, backgroundColor: '#fff'},
    },
    paths: 'page/main',
    mode: 'card',
    headerMode: 'screen',
    cardStyle: {backgroundColor: "#ffffff"},
    transitionConfig: (() => ({
        screenInterpolator: CardStackStyleInterpolator.forHorizontal,
    })),
    onTransitionStart: (() => {
        console.log('页面跳转动画开始');
    }),
    onTransitionEnd: (() => {
        console.log('页面跳转动画结束');
    }),
};
  • initialRouteName - 导航器组件中初始显示页面的路由名称,如果不设置,则默认第一个路由页面为初始显示页面
  • initialRouteParams - 给初始路由的参数,在初始显示的页面中可以通过this.props.navigation.state.params来获取
  • navigationOptions - 路由页面的配置选项,它会被RouteConfigs 参数中的 navigationOptions的对应属性覆盖。
  • paths - 路由中设置的路径的覆盖映射配置
  • mode - 页面跳转方式,有cardmodal两种,默认为card
    • card - 原生系统默认的的跳转
    • modal - 只针对iOS平台,模态跳转
  • headerMode - 页面跳转时,头部的动画模式,有floatscreennone三种:
    • float - 渐变,类似iOS的原生效果
    • screen - 标题与屏幕一起淡入淡出
    • none - 没有动画
  • cardStyle - 为各个页面设置统一的样式,比如背景色,字体大小等
  • transitionConfig - 配置页面跳转的动画,覆盖默认的动画效果
  • onTransitionStart - 页面跳转动画即将开始时调用
  • onTransitionEnd - 页面跳转动画一旦完成会马上调用

页面的配置选项navigationOptions通常还可以在对应页面中去静态配置,比如在HomePage页面中:

export default class HomePage extends Component {

    // 配置页面导航选项
    static navigationOptions = ({navigation}) => ({
        title: 'HOME',
        titleStyle: {color: '#ff00ff'},
        headerStyle:{backgroundColor:'#000000'}
    });

    render() {
        return (
            <View></View>
        )
    };
}

同样地,在页面里面采用静态的方式配置navigationOptions中的属性,会覆盖StackNavigator构造函数中两个参数RouteConfigsStackNavigatorConfig配置的navigationOptions里面的对应属性。navigationOptions中属性的优先级是:
页面中静态配置 > RouteConfigs > StackNavigatorConfig

有了RouteConfigsStackNavigatorConfig两个参数,就可以构造出一个导航器组件StackNavigator,直接引用该组件:

const Navigator = StackNavigator(RouteConfigs, StackNavigatorConfig);

export default class MainComponent extends Component {
    render() {
        return (
            <Navigator/>
        )
    };
}

已经配置好导航器以及对应的路由页面了,但是要完成页面之间的跳转,还需要navigation

navigation

在导航器中的每一个页面,都有navigation属性,该属性有以下几个属性/方法:

  • navigate - 跳转到其他页面
  • state - 当前页面导航器的状态
  • setParams - 更改路由的参数
  • goBack - 返回
  • dispatch - 发送一个action
navigete

调用这个方法可以跳转到导航器中的其他页面,此方法有三个参数:
routeName 导航器中配置的路由名称
params 传递参数到下一个页面
action action
比如:this.props.navigation.navigate('Find', {param: 'i am the param'});

state

state里面包含有传递过来的参数paramskey、路由名称routeName,打印log可以看得到:

{ 
  params: { param: 'i am the param' },
  key: 'id-1500546317301-1',
  routeName: 'Mine' 
}
setParams

更改当前页面路由的参数,比如可以用来更新头部的按钮或者标题。

componentDidMount() {
    this.props.navigation.setParams({param:'i am the new param'})
}
goBack

回退,可以不传,也可以传参数,还可以传null

this.props.navigation.goBack();       // 回退到上一个页面
this.props.navigation.goBack(null);   // 回退到任意一个页面
this.props.navigation.goBack('Home'); // 回退到Home页面

TabNavigator

TabNavigator,即是Tab选项卡,类似于原生android中的TabLayout,它的构造函数:

TabNavigator(RouteConfigs, TabNavigatorConfig)

api和StackNavigator类似,参数RouteConfigs是路由配置,参数TabNavigatorConfig是Tab选项卡配置。

RouteConfigs

路由配置和StackNavigator中是一样的,配置路由以及对应的screen页面,navigationOptions为对应路由页面的配置选项:

  • title - Tab标题,可用作headerTitletabBarLabel回退标题
  • tabBarVisible - Tab的是否可见,没有设置的话默认为true
  • tabBarIcon - Tab的icon组件,可以根据{focused: boolean, tintColor: string}方法来返回一个icon组件
  • tabBarLabel - Tab中显示的标题字符串或者组件,也可以根据{ focused: boolean, tintColor: string }方法返回一个组件
TabNavigatorConfig
  • tabBarComponent - Tab选项卡组件,有TabBarBottomTabBarTop两个值,在iOS中默认为TabBarBottom,在Android中默认为TabBarTop
    • TabBarTop - 在页面的顶部
    • TabBarBottom - 在页面的底部
  • tabBarPosition - Tab选项卡的位置,有 topbottom两个值
  • swipeEnabled - 是否可以滑动切换Tab选项卡
  • animationEnabled - 点击Tab选项卡切换界面是否需要动画
  • lazy - 是否懒加载页面
  • initialRouteName - 初始显示的Tab对应的页面路由名称
  • order - 用路由名称数组来表示Tab选项卡的顺序,默认为路由配置顺序
  • paths - 路径配置
  • backBehavior - androd点击返回键时的处理,有initialRoutenone两个值
    • initailRoute - 返回初始界面
    • none - 退出
  • tabBarOptions - Tab配置属性,用在TabBarTopTabBarBottom时有些属性不一致:
    • 用于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的样式
底部Tab导航示例
import React, {Component} from 'react';
import {StackNavigator, TabBarBottom, TabNavigator} from "react-navigation";
import HomeScreen from "./index18/HomeScreen";
import NearByScreen from "./index18/NearByScreen";
import MineScreen from "./index18/MineScreen";
import TabBarItem from "./index18/TabBarItem";
export default class MainComponent extends Component {
    render() {
        return (
            <Navigator/>
        );
    }
}

const TabRouteConfigs = {
    Home: {
        screen: HomeScreen,
        navigationOptions: ({navigation}) => ({
            tabBarLabel: '首页',
            tabBarIcon: ({focused, tintColor}) => (
                <TabBarItem
                    tintColor={tintColor}
                    focused={focused}
                    normalImage={require('./img/tabbar/pfb_tabbar_homepage_2x.png')}
                    selectedImage={require('./img/tabbar/pfb_tabbar_homepage_selected_2x.png')}
                />
            ),
        }),
    },
    NearBy: {
        screen: NearByScreen,
        navigationOptions: {
            tabBarLabel: '附近',
            tabBarIcon: ({focused, tintColor}) => (
                <TabBarItem
                    tintColor={tintColor}
                    focused={focused}
                    normalImage={require('./img/tabbar/pfb_tabbar_merchant_2x.png')}
                    selectedImage={require('./img/tabbar/pfb_tabbar_merchant_selected_2x.png')}
                />
            ),
        },
    }
    ,
    Mine: {
        screen: MineScreen,
        navigationOptions: {
            tabBarLabel: '我的',
            tabBarIcon: ({focused, tintColor}) => (
                <TabBarItem
                    tintColor={tintColor}
                    focused={focused}
                    normalImage={require('./img/tabbar/pfb_tabbar_mine_2x.png')}
                    selectedImage={require('./img/tabbar/pfb_tabbar_mine_selected_2x.png')}
                />
            ),
        },
    }
};
const TabNavigatorConfigs = {
    initialRouteName: 'Home',
    tabBarComponent: TabBarBottom,
    tabBarPosition: 'bottom',
    lazy: true,
};
const Tab = TabNavigator(TabRouteConfigs, TabNavigatorConfigs);
const StackRouteConfigs = {
    Tab: {
        screen: Tab,
    }
};
const StackNavigatorConfigs = {
    initialRouteName: 'Tab',
    navigationOptions: {
        title: '标题',
        headerStyle: {backgroundColor: '#5da8ff'},
        headerTitleStyle: {color: '#333333'},
    }
};
const Navigator = StackNavigator(StackRouteConfigs, StackNavigatorConfigs);
顶部Tab选项卡示例
import React, {Component} from "react";
import {StackNavigator, TabBarTop, TabNavigator} from "react-navigation";
import HomeScreen from "./index18/HomeScreen";
import NearByScreen from "./index18/NearByScreen";
import MineScreen from "./index18/MineScreen";
export default class MainComponent extends Component {
    render() {
        return (
            <Navigator/>
        );
    }
}

const TabRouteConfigs = {
    Home: {
        screen: HomeScreen,
        navigationOptions: ({navigation}) => ({
            tabBarLabel: '首页',
        }),
    },
    NearBy: {
        screen: NearByScreen,
        navigationOptions: {
            tabBarLabel: '附近',
        },
    }
    ,
    Mine: {
        screen: MineScreen,
        navigationOptions: {
            tabBarLabel: '我的',
        },
    }
};
const TabNavigatorConfigs = {
    initialRouteName: 'Home',
    tabBarComponent: TabBarTop,
    tabBarPosition: 'top',
    lazy: true,
    tabBarOptions: {}
};
const Tab = TabNavigator(TabRouteConfigs, TabNavigatorConfigs);
const StackRouteConfigs = {
    Tab: {
        screen: Tab,
    }
};
const StackNavigatorConfigs = {
    initialRouteName: 'Tab',
    navigationOptions: {
        title: '标题',
        headerStyle: {backgroundColor: '#5da8ff'},
        headerTitleStyle: {color: '#333333'},
    }
};
const Navigator = StackNavigator(StackRouteConfigs, StackNavigatorConfigs);

DrawerNavigator

在原生Android MD 风格里面很多app都会采用侧滑抽屉来做主页面的导航,利用DrawerNavigator在RN中可以很方便来实现抽屉导航。

DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)

DrawerNavigator的构造函数一样,参数配置也类似。

RouteConfigs

抽屉导航的路由配置RouteConfigs,和TabNavigator的路由配置完全一样,screen配置对应路由页面,navigationOptions为对应页面的抽屉配置选项:

  • title - 抽屉标题,和headerTitledrawerLabel一样
  • drawerLabel - 标签字符串,或者自定义组件, 可以根据{ focused: boolean, tintColor: string }函数来返回一个自定义组件作为标签
  • drawerIcon - 抽屉icon,可以根据{ focused: boolean, tintColor: string }函数来返回一个自定义组件作为icon
DrawerNavigatorConfig

抽屉配置项属性:

  • drawerWidth - 抽屉宽度,可以使用Dimensions获取屏幕的宽度,动态计算
  • drawerPosition - 抽屉位置,可以是left或者right
  • contentComponent - 抽屉内容组件,可以自定义侧滑抽屉中的所有内容,默认为DrawerItems
  • contentOptions - 用来配置抽屉内容的属性。当用来配置DrawerItems是配置属性选项:
    • items - 抽屉栏目的路由名称数组,可以被修改
    • activeItemKey - 当前选中页面的key id
    • activeTintColor - 选中条目状态的文字颜色
    • activeBackgroundColor - 选中条目的背景色
    • inactiveTintColor - 未选中条目状态的文字颜色
    • inactiveBackgroundColor - 未选中条目的背景色
    • onItemPress(route) - 条目按下时会调用此方法
    • style - 抽屉内容的样式
    • labelStyle - 抽屉的条目标题/标签样式
  • initialRouteName - 初始化展示的页面路由名称
  • order - 抽屉导航栏目顺序,用路由名称数组表示
  • paths - 路径
  • backBehavior - androd点击返回键时的处理,有initialRoute和none两个值,initailRoute:返回初始界面,none:退出
抽屉导航示例
import React, {Component} from 'react';
import {DrawerNavigator, StackNavigator, TabBarBottom, TabNavigator} from "react-navigation";
import HomeScreen from "./index18/HomeScreen";
import NearByScreen from "./index18/NearByScreen";
import MineScreen from "./index18/MineScreen";
import TabBarItem from "./index18/TabBarItem";
export default class MainComponent extends Component {
    render() {
        return (
            <Navigator/>
        );
    }
}
const DrawerRouteConfigs = {
    Home: {
        screen: HomeScreen,
        navigationOptions: ({navigation}) => ({
            drawerLabel : '首页',
            drawerIcon : ({focused, tintColor}) => (
                <TabBarItem
                    tintColor={tintColor}
                    focused={focused}
                    normalImage={require('./img/tabbar/pfb_tabbar_homepage_2x.png')}
                    selectedImage={require('./img/tabbar/pfb_tabbar_homepage_selected_2x.png')}
                />
            ),
        }),
    },
    NearBy: {
        screen: NearByScreen,
        navigationOptions: {
            drawerLabel : '附近',
            drawerIcon : ({focused, tintColor}) => (
                <TabBarItem
                    tintColor={tintColor}
                    focused={focused}
                    normalImage={require('./img/tabbar/pfb_tabbar_merchant_2x.png')}
                    selectedImage={require('./img/tabbar/pfb_tabbar_merchant_selected_2x.png')}
                />
            ),
        },
    },
    Mine: {
        screen: MineScreen,
        navigationOptions: {
            drawerLabel : '我的',
            drawerIcon : ({focused, tintColor}) => (
                <TabBarItem
                    tintColor={tintColor}
                    focused={focused}
                    normalImage={require('./img/tabbar/pfb_tabbar_mine_2x.png')}
                    selectedImage={require('./img/tabbar/pfb_tabbar_mine_selected_2x.png')}
                />
            ),
        },
    }
};
const DrawerNavigatorConfigs = {
    initialRouteName: 'Home',
    tabBarComponent: TabBarBottom,
    tabBarPosition: 'bottom',
    lazy: true,
    tabBarOptions: {}
};
const Drawer = DrawerNavigator(DrawerRouteConfigs, DrawerNavigatorConfigs);
const StackRouteConfigs = {
    Drawer: {
        screen: Drawer,
    }
};
const StackNavigatorConfigs = {
    initialRouteName: 'Drawer',
    navigationOptions: {
        title: '标题',
        headerStyle: {backgroundColor: '#5da8ff'},
        headerTitleStyle: {color: '#333333'},
    }
};
const Navigator = StackNavigator(StackRouteConfigs, StackNavigatorConfigs);

源码:https://gitee.com/xiaojianjun/DD.git (index20.js、index21.js、index22.js)

参考

https://reactnavigation.org/docs/
ReactNative导航新宠儿react-navigation

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容