react navigation使用介绍

3,059 阅读11分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

此文为V1版本,最新版为V6,请谨慎阅读。

在很久之前,RN中文网说推荐用react-navigation替代navigator作为新的导航库,从RN 0.43版本开始,官方就已经停止维护Navigator了,所以强烈建议大家迁移到新的react-navigation库,而且新的导航库无论从性能还是易用性上都要大大好于老的Navigator!

附上英文文档地址,

这个是我自己写的导航例子:github.com/lizhuoyuan/…

推荐直接看事例,注释清楚.逻辑较为容易理解

接下来我们看react-navigation的使用。

一 StackNavigator

1.下载和安装

 在项目根目录执行:

  npm install --save react-navigation

2.在js文件中引入我们需要的组件

   import {StackNavigator} from 'react-navigation';

3.开始使用

import Home from './Home';
import Mains from './Second'

const App = StackNavigator({
    Home: {screen: Home},
    Chat: {screen: Second},
    Two: {screen: Mains}
});
export default App;


在index.android.js 或者index.ios.js中引入app

在StackNavigator中 把我们需要跳转的页面都加进去。

然后给每个页面设置标题

export default class Home extends React.Component {


    static navigationOptions = {
        title: 'Welcome',
    };


会在标题栏显示 Welcome的字样。

接下来是跳转


使用navigate()方法来执行跳转

navigate('Chat', {user:user})

前面chat为你定义的页面名字,后面{}内包括你要传的参数,可为空,

例如  navigate('Chat'),

代码如下:

    render() {
        const {navigate} = this.props.navigation;
        let user = {'name': 'zy', age: 18}
        return (
            <View>
                <Text onPress={() => navigate('Chat', {user:user})}>Home</Text>
            </View>
        )
    }
}

 

在Chat页面写接收参数的方法:

render() {
        const {navigate} = this.props.navigation;
        let {params} = this.props.navigation.state;
        return (
            <View>
                <Text>Second {params.user.name}</Text>
            </View>
        )
    }

这样,text组件上就会显示你传过来的参数,例如我之前传来的是name为zy的一个对象,那么这里就会显示出Second zy。

从第一个页面跳转到第二个页面的话,第二个页面会有个回退按钮,返回到前一个页面。

class Second extends React.Component {


    static navigationOptions = ({navigation}) => ({
        title: ` ${navigation.state.params.user.name}`,       //前一个页面传来的对象的name属性
    })


    render() {
        const {navigate} = this.props.navigation;
        let {params} = this.props.navigation.state;
        return (
            <View>
                <Text onPress={() => navigate('Home')}>Second {params.user.name}</Text>
            </View>
        )
    }
}


class Three extends React.Component {
    static navigationOptions = ({navigation}) => ({
        title: ` ${navigation.state.params.user.age}`,
    })

    render() {
        const {navigate} = this.props.navigation;
        let {params} = this.props.navigation.state;
        var name = params.name;
        return (
            <View>
                <Text>three : {params.user.age}</Text>
            </View>
        )
    }
}

const MainSceen = TabNavigator({
    l1: {screen: Second},
    l2: {screen: Three}
})
export default MainSceen;

当然,这样做之后我们要把 MainSceen 这个组件添加到StackNavigator中,

像这样:

const App = StackNavigator({
    Home: {screen: Home},
  //  Chat: {screen: Second},
    Two: {screen: Mains}
});

 

再跳转的话直接navigate('Two')就可以,如果你不需要传递参数的话。

然后我们给标题栏添加个右边的按钮

static navigationOptions = ({navigation}) => ({
    title: ` ${navigation.state.params.user.name}`,
    headerRight:<Button title={'标题'}/>
})

当然你也可以换成其他组件,也可以添加点击事件等等。也可以一起配。

这个navigationOptions也可以在最开始的StackNavigator中配置:

const App = StackNavigator({
    Home: {
        screen: Home,
        navigationOptions: {
            headerTitle: 'Home',   //headerTitle和title效果相同 设置导航栏标题,推荐用这个方法
            headerTitleStyle: {color: 'red', backgroundColor: 'white', alignSelf: 'center'},   //标题栏文字样式 设置居中
            headerStyle: {backgroundColor: 'green'},  //导航栏的样式
            //header: null                              //隐藏导航栏
            headerRight: <Text onPress={() => {
                alert('i am right');
            }
            }>right</Text>,                          //标题栏左右的按钮
            headerLeft: <Text style={{marginLeft: 10}}>left</Text>,           //最好定义在组件内部
        }
    },
    First: {
        screen: First,
        navigationOptions: ({navigation}) => ({
            headerTitle: 'i am first',
            headerStyle: {backgroundColor: 'green'},  //导航栏的样式
            headerTitleStyle: {color: 'red', alignSelf: 'center', backgroundColor: 'white'},
            headerLeft: <Button title={'go back'} onPress={() => {
                navigation.goBack();
            }}/>,
        })

    },
    Second: {
        screen: Second,
        navigationOptions: {}
    },
    Tab: {
        screen: Tab,
        navigationOptions: {
            title: 'Tab',
        }
    },
});

上面在通用属性中,配置了一个右侧按钮,那么在每一个页面都会有这样一个按钮

它的属性有:

StackNavigatorConfig  

路由器的选项:

  • initialRouteName - 设置堆栈的默认屏幕。必须匹配路由配置中的一个密钥。也就是已有的路由名字
  • initialRouteParams - 初始路线的参数
  • navigationOptions - 用于屏幕的默认导航选项
  • paths - 路由配置中设置的路径的覆盖映射

视觉选项:

  • mode - 定义渲染和转换的样式:

    • card - 使用标准的iOS和Android屏幕转换。这是默认值。
    • modal - 使屏幕从底部滑入,这是普通的iOS模式。只适用于iOS,对Android无影响。
  • headerMode - 指定标题应如何呈现:

    • float - 渲染一个保持在顶部的标题,并且随着画面的改变而呈现动画。这是iOS上的常见模式。
    • screen - 每个屏幕都有一个标题,标题与屏幕一起淡入淡出。这是Android上的常见模式。
    • none - 不会显示标题。
  • cardStyle - 使用此支路覆盖或扩展堆叠中单个卡的默认样式。

  • transitionConfig - 返回覆盖默认屏幕转换的对象的功能。

  • onTransitionStart - 卡转换动画即将开始时调用的功能。

  • onTransitionEnd - 卡转换动画完成后要调用的功能。

接下来看一下navigationOptions的参数:

title 

串可以用作回退和headerTitle``tabBarLabel

header 

React元素或给定的函数返回一个React元素,以显示为标题。设置隐藏标题。HeaderProps``null

headerTitle 

标题使用的字符串或React元素。默认为场景title

headerBackTitle 

iOS上的后退按钮使用的标题字符串或禁用标签。默认为场景null``title

headerTruncatedBackTitle 

当返回按钮不适合屏幕时使用的标题字符串。默认。headerBackTitle``"Back"

headerRight 

反应元素显示在标题的右侧

headerLeft 

反应元素显示在标题的左侧

headerStyle 

标题的样式对象

headerTitleStyle 

标题组件的样式对象

headerBackTitleStyle 

样式对象为后面的标题

headerTintColor 

标题颜色

headerPressColorAndroid 

颜色纹理(Android> = 5.0)

gesturesEnabled 

是否可以使用手势关闭此屏幕。在iOS上默认为true,在Android上为false。

二. TabNavigator

然后我们看一下另一个常用组件TabNavigator的使用,用于带有多个选项卡的屏幕,相当于android中的tab,可以来回切换。

1.引入组件

import {TabNavigator} from 'react-navigation';

2.开始使用

可以给每个页面单独设置标题,切换到对应的tab会自动切换标题,也可以用从前一个页面传来的参数中的内容当标题

 

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */
import React from 'react';
import {Image,} from 'react-native';
import {TabNavigator} from 'react-navigation';
import HomePage from './app/home/HomePage';
import More from './app/more/More';
import MePage from './app/mepage/Me';


const App = TabNavigator({
    HomePage: {
        screen: HomePage,
        navigationOptions: {
            tabBarLabel: '首页',    //若不设置,则以key为标题
            tabBarVisible: true,  //是否隐藏标签栏。默认不隐藏(true),该选项卡激活时生效
            tabBarIcon: ({tintColor}) => (<Image style={{height: 30, resizeMode: 'contain', tintColor: tintColor}}
                                                 source={require('./img/ic_launcher.png')}/>)
        },

    },
    More: {
        screen: More,
        navigationOptions: {
            // tabBarLabel: '首页',
            tabBarVisible: true,  //是否隐藏标签栏。默认不隐藏(true),该选项卡激活时生效
            tabBarIcon: ({tintColor}) => (<Image style={{height: 30, resizeMode: 'contain', tintColor: tintColor}}
                                                 source={require('./img/ic_launcher.png')}/>)
        },
    },
    MePage: {
        screen: MePage,
        navigationOptions: {
            //   tabBarLabel: '首页',
            tabBarVisible: true,  //是否隐藏标签栏。默认不隐藏(true),该选项卡激活时生效
            tabBarIcon: ({tintColor}) => (<Image style={{height: 30, resizeMode: 'contain', tintColor: tintColor}}
                                                 source={require('./img/ic_launcher.png')}/>)
        },
    },

}, {
    tabBarPosition: 'bottom',    //设置tabbar的位置,iOS默认在底部,安卓默认在顶部。(属性值:'top','bottom')
    swipeEnabled: true,          //是否允许在标签之间滑动
    animationEnabled: false,     //是否在更改标签时显示动画。
    lazy: true,                  //是否根据需要懒惰呈现标签,而不是提前制作,意思是在app打开的时候将底部标签栏全部加载,默认false,推荐改成true哦
    initialRouteName: 'More',    //设置默认的页面组件
    backBehavior: 'none',        //按 back 键是否跳转到第一个Tab(首页), none 为不跳转
    tabBarOptions: {
        activeTintColor: 'green',//label和icon的前景色 活跃状态下(选中)。
        activeBackgroundColor: 'red', //label和icon的背景色 活跃状态下(选中) 。
        showLabel: true,         //是否显示label,默认开启
        labelStyle: {fontSize: 12}, //label的样式
        style: {height: 50},  //tabbar的样式
        iconStyle: {height: 30}   //安卓,
    }
});

export default App;
const MyApp = TabNavigator({
        Home: {
            screen: Home,
            navigationOptions: {  //也可以写在组件内部的static navigationOptions内
                tabBarLabel: '首页',
                tabBarIcon: ({tintColor}) => (<Image source={require('./images/camera.png')}
                                                     style={{tintColor: tintColor}}/>)
            }

        },
        Notifications: {
            screen: Two,
            navigationOptions: {
                tabBarLabel: '2页',
                tabBarIcon: ({tintColor}) => (<Image source={require('./images/add.png')}
                                                     style={[{tintColor: tintColor}, styles.icon]}/>)
            }

        },
        Me: {
            screen: Three,
            navigationOptions: {
                tabBarLabel: '3页',
                tabBarIcon: ({tintColor}) => (<Image source={require('./images/more.png')}
                                                     style={{tintColor: tintColor}}/>)
            }
        }
    },
    {
        animationEnabled: false, // 切换页面时是否有动画效果
        tabBarPosition: 'bottom', // 显示在底端,android 默认是显示在页面顶端的
        swipeEnabled: true, // 是否可以左右滑动切换tab
        backBehavior: 'none', // 按 back 键是否跳转到第一个Tab(首页), none 为不跳转
        tabBarOptions: {
            activeTintColor: '#ff8500', // 文字和图片选中颜色
            inactiveTintColor: '#999', // 文字和图片未选中颜色
            showIcon: true, // android 默认不显示 icon, 需要设置为 true 才会显示
            indicatorStyle: {
                height: 0  // 如TabBar下面显示有一条线,可以设高度为0后隐藏
            },
            style: {
                backgroundColor: '#fff', // TabBar 背景色
                // height: 44
            },
            labelStyle: {
                fontSize: 10, // 文字大小
            },
        },
    });

3.常用属性介绍

再看一下API

API定义 

TabNavigator(RouteConfigs, TabNavigatorConfig)

第一个参数RouteConfigs  :

RouteConfigs  对象是从路由名称映射到一个路由配置,它告诉导航以呈现该路线什么,参照 StackNavigator

第二个参数:TabNavigatorConfig  

  • tabBarComponent- 要用作标签栏的组件,例如 (这是iOS上的默认设置), (这是Android上的默认设置)TabBarBottom``TabBarTop
  • tabBarPosition- 标签栏的位置可以是或'top'``'bottom'
  • swipeEnabled - 是否允许在标签之间进行滑动
  • animationEnabled - 是否在更改标签时进行动画处理
  • lazy - 是否根据需要懒惰呈现标签,而不是提前制作
  • tabBarOptions - 配置标签栏,如下所示。

几个选项被传递到底层路由器来修改导航逻辑:

  • initialRouteName - 第一次加载时初始标签路由的routeName
  • order - 定义选项卡顺序的routeNames数组
  • paths - 将routeName映射到路径配置,该配置将覆盖routeConfigs中设置的路径。
  • backBehavior - 后退按钮是否会使Tab键切换到初始选项卡?如果是的话,设置为,否则。默认为行为。initialRoute``none``initialRoute

tabBarOptionsfor (iOS上的默认标签栏)TabBarBottom 

  • activeTintColor - 活动标签的标签和图标颜色
  • activeBackgroundColor - 活动选项卡的背景颜色
  • inactiveTintColor - 不活动标签的标签和图标颜色
  • inactiveBackgroundColor - 非活动标签的背景颜色
  • showLabel - 是否显示标签的标签,默认为true
  • style - 标签栏的样式对象
  • labelStyle - 选项卡标签的样式对象
  • tabStyle - 标签的样式对象

例:

tabBarOptions: {
  activeTintColor: '#e91e63',
  labelStyle: {
    fontSize: 12,
  },
  style: {
    backgroundColor: 'blue',
  },
}

tabBarOptionsfor (Android上的默认标签栏)TabBarTop 

  • activeTintColor - 活动标签的标签和图标颜色
  • inactiveTintColor - 不活动标签的标签和图标颜色
  • showIcon - 是否显示标签的图标,默认值为false
  • showLabel - 是否显示标签的标签,默认为true
  • upperCaseLabel - 是否使标签大写,默认为true
  • pressColor - 颜色纹理(Android> = 5.0)
  • pressOpacity - 按压标签的不透明度(iOS和Android <5.0 only)
  • scrollEnabled - 是否启用可滚动选项卡
  • tabStyle - 标签的样式对象
  • indicatorStyle - 标签指示器的样式对象(选项卡底部的行)
  • labelStyle - 选项卡标签的样式对象
  • iconStyle - 标签图标的样式对象
  • style - 标签栏的样式对象

例:

tabBarOptions: {
  labelStyle: {
    fontSize: 12,
  },
  tabStyle: {
    width: 100,    
  },
  style: {
    backgroundColor: 'blue',
  },
}

NavigationOptions:

title 

通用标题可以用作备用和headerTitle``tabBarLabel

tabBarVisible 

True或false显示或隐藏选项卡栏,如果未设置,则默认为true

tabBarIcon 

React Element或者一个给定的函数返回一个React.Element,以在tab栏中显示{ focused: boolean, tintColor: string }

tabBarLabel 

标签栏或React元素中显示的标签的标题字符串或者给定的函数返回一个React.Element,以在标签栏中显示。当未定义时,使用场景。要隐藏,请参见上一节。{ focused: boolean, tintColor: string }``title``tabBarOptions.showLabel

三.DrawerNavigator 

/**
 * Created by 卓原 on 2017/10/31.
 * zhuoyuan93@gmail.com
 */

import React from 'react';
import {
    View,
    Text,
    StyleSheet,
    Button,
    Image
} from 'react-native';

import {DrawerNavigator} from 'react-navigation';

class Home extends React.Component {
    static navigationOptions = {
        drawerLabel: 'Notifications标题',
        drawerIcon: ({tintColor}) => (
            <Image
                source={require('../../img/ic_launcher.png')}
                style={[styles.icon, {tintColor: tintColor}]}
            />
        ),
    };
    render() {
        const {navigate} = this.props.navigation;
        return (
            <View style={styles.container}>
                <Text onPress={() =>
                    navigate('Home2', {name: '从Home到HOme2'})
                }>跳到新页面</Text>

                <Text onPress={() =>
                    navigate('DrawerOpen')
                }>打开抽屉</Text>
            </View>
        )
    }
}

class MyNotificationsScreen extends React.Component {
    static navigationOptions = {
        drawerLabel: 'Notifications标题',
        drawerIcon: ({tintColor}) => (
            <Image
                source={require('../../img/ic_launcher.png')}
                style={[styles.icon, {tintColor: tintColor}]}
            />
        ),
    };

    render() {
        return (
            <Button
                onPress={() => this.props.navigation.goBack()}
                title="Go back home"
            />
        );
    }
}

const Drawer = DrawerNavigator({
    Home: {
        screen: Home,
        navigationOptions:{
            drawerLabel:'帅气Home',
            headerTitle:'home title',
            drawerIcon: ({tintColor}) => (
                <Image
                    source={require('../../img/ic_launcher.png')}
                    style={[styles.icon, {tintColor: tintColor}]}
                />
            ),
        }
    },

    Notifications: {
        screen: MyNotificationsScreen,
    },
    Notifications2: {
        screen: MyNotificationsScreen,
    },
}, {
    drawerWidth: 200, //抽屉的宽度
    drawerPosition: 'left' ,  //选项是left和right.默认是left
   // contentComponent:(navigation)=><Text>asa</Text>,
    contentOptions: {
        activeTintColor: '#e91e63',
        itemsContainerStyle: {
            marginVertical: 0,
        },
        iconContainerStyle: {
            opacity: 1
        },
    }

});

const styles = StyleSheet.create({
    container: {
        marginTop: 22
    },
    icon: {
        width: 24,
        height: 24,
    },
});

export default Drawer;

用于轻松设置带抽屉导航的屏幕。有关实例,请参阅我们的展会演示

class MyHomeScreen extends React.Component {
  static navigationOptions = {
    drawerLabel: 'Home',
    drawerIcon: ({ tintColor }) => (
      <Image
        source={require('./chats-icon.png')}
        style={[styles.icon, {tintColor: tintColor}]}
      />
    ),
  };

  render() {
    return (
      <Button
        onPress={() => this.props.navigation.navigate('Notifications')}
        title="Go to notifications"
      />
    );
  }
}

class MyNotificationsScreen extends React.Component {
  static navigationOptions = {
    drawerLabel: 'Notifications',
    drawerIcon: ({ tintColor }) => (
      <Image
        source={require('./notif-icon.png')}
        style={[styles.icon, {tintColor: tintColor}]}
      />
    ),
  };

  render() {
    return (
      <Button
        onPress={() => this.props.navigation.goBack()}
        title="Go back home"
      />
    );
  }
}

const styles = StyleSheet.create({
  icon: {
    width: 24,
    height: 24,
  },
});

const MyApp = DrawerNavigator({
  Home: {
    screen: MyHomeScreen,
  },
  Notifications: {
    screen: MyNotificationsScreen,
  },
});

打开和关闭抽屉,导航到并分别。'DrawerOpen'``'DrawerClose'

this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer

API定义 

DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)

RouteConfigs  

路由CONFIGS对象是从路由名称映射到一个路由配置,它告诉导航以呈现该路线什么,参见例如由。StackNavigator

DrawerNavigatorConfig  

  • drawerWidth - 抽屉的宽度
  • drawerPosition- 选项是或。默认是位置。left``right``left
  • contentComponent - 用于呈现抽屉内容的组件,例如导航项。接收抽屉的支柱。默认为。有关详细信息,请参阅下文。navigation``DrawerItems
  • contentOptions - 配置抽屉内容,见下文。

示例: 

默认是不可滚动。要实现可滚动,您必须使用该属性定制容器,如下面的示例所示。DrawerView``View``contentComponent

{
  drawerWidth: 200,
  drawerPosition: 'right',
  contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>
}

几个选项被传递到底层路由器来修改导航逻辑:

  • initialRouteName - 初始路由的routeName。
  • order - 定义抽屉物品顺序的routeNames数组。
  • paths - 将routeName映射到路径配置,该配置将覆盖routeConfigs中设置的路径。
  • backBehavior - 后退按钮是否会切换到初始路线?如果是的话,设置为,否则。默认为行为。initialRoute``none``initialRoute

提供自定义contentComponent 

您可以轻松地覆盖所使用的默认组件:react-navigation

import { DrawerItems } from 'react-navigation';

const CustomDrawerContentComponent = (props) => (
  <View style={style.container}>
    <DrawerItems {...props} />
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});

contentOptionsDrawerItems 

  • items - 路由数组,可以修改或覆盖
  • activeItemKey - 标识活动路线的钥匙
  • activeTintColor - 活动标签的标签和图标颜色
  • activeBackgroundColor - 活动标签的背景颜色
  • inactiveTintColor - 无效标签的标签和图标颜色
  • inactiveBackgroundColor - 非活动标签的背景颜色
  • onItemPress(route) - 按下项目时调用的功能
  • style - 内容部分的样式对象
  • labelStyle- 当您的标签是字符串时,样式对象将覆盖内容部分中的样式Text

示例: 

contentOptions: {
  activeTintColor: '#e91e63',
  style: {
    marginVertical: 0,
  }
}

屏幕导航选项 

title 

通用标题可以用作备用和headerTitle``drawerLabel

drawerLabel 

String,React元素或给定的函数返回一个React.Element,显示在抽屉侧边栏中。当不确定,现场使用{ focused: boolean, tintColor: string }``title

drawerIcon 

React Element或一个函数,返回一个React.Element,显示在抽屉侧边栏中{ focused: boolean, tintColor: string }

导航道具 

创建的导航器组件需要以下道具:DrawerNavigator(...)

  • screenProps - 向儿童屏幕传递额外的选项,例如:
const DrawerNav = DrawerNavigator({
  // config
});

<DrawerNav
  screenProps={/* this prop will get passed to the screen components and nav options as props.screenProps */}
/>

嵌套DrawerNavigation 

请记住,如果您嵌套DrawerNavigation,抽屉将显示在父导航下方。

withNavigation

withNavigation是一个更高阶的组件,它将导航道具传递给一个包装组件。当您无法直接将导航道具传递到组件时,或者在深度嵌套子节点的情况下不希望传递导航道具时,它非常有用。

import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';

class MyBackButton extends React.Component {
  render() {
    return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
  }
}

// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);