react-navigation使用技巧

前端之家收集整理的这篇文章主要介绍了react-navigation使用技巧前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本文是基于react-navigation^1.0.0-beta.9来书写的。

如果遇到什么问题可以在评论回复,或者加QQ群397885169讨论

识兔,一款用来识别图片的开源项目,在未来还会添加更多有意思的东西

react-navigation的Demo

react-navigation使用技巧(进阶篇)

什么是react-navigation?

react-native从开源至今,一直存在几个无法解决的毛病,偶尔就会复发让人隐隐作痛,提醒你用的不是原生,其中包括列表的复用问题,导航跳转不流畅的问题等等。
终于facebook坐不住了,在前一段时间开始推荐使用react-navigation,并且在0.44发布的时将之前一直存在的Navigator废弃了。
react-navigation是致力于解决导航卡顿,数据传递,Tabbar和navigator布局,支持redux。虽然现在功能还不完善,但基本是可以在项目中推荐使用的。

属性

react-navigation分为三个部分。
StackNavigator类似顶部导航条,用来@R_545_404@面和传递参数。
TabNavigator类似底部标签栏,用来区分模块。
DrawerNavigator抽屉,类似从App左侧滑出一个页面,具体我没有使用过,在这里不做讲解。
下面会分开讲解官网提供的配置方法,但顺序可能会官网不一样,因为我认为有些东西可能用不到的只会说一下。

StackNavigator 基础用法/属性介绍

const MyApp = StackNavigator({
    // 对应界面名称
    MyTab: {
        screen: MyTab,},Detail: {
        screen: Detail,navigationOptions:{
            headerTitle:'详情',headerBackTitle:null,}
    },{
    headerMode: 'screen',});

导航配置

screen:对应界面名称,需要填入import之后的页面

navigationOptions:配置StackNavigator的一些属性

  • title标题,如果设置了这个导航栏和标签栏的title就会变成一样的,所以不推荐使用这个方法
  • header:可以设置一些导航的属性,当然如果想隐藏顶部导航条只要将这个属性设置为null就可以了。
  • headerTitle:设置导航栏标题,推荐用这个方法
  • headerBackTitle:设置@R_545_404@面左侧返回箭头后面的文字,默认是上一个页面标题。可以自定义,也可以设置为null
  • headerTruncatedBackTitle:设置当上个页面标题不符合返回箭头后的文字时,默认改成"返回"。(上个页面标题过长,导致显示不下,所以改成了短一些的。)
  • headerRight:设置导航条右侧。可以是按钮或者其他。
  • headerLeft:设置导航条左侧。可以是按钮或者其他。
  • headerStyle:设置导航条的样式。背景色,宽高等。如果想去掉安卓导航条底部阴影可以添加elevation: 0,iOS下用shadowOpacity: 0。
  • headerTitleStyle:设置导航条文字样式。安卓上如果要设置文字居中,只要添加alignSelf:'center'就可以了
  • headerBackTitleStyle:设置导航条返回文字样式。
  • headerTintColor:设置导航栏文字颜色。总感觉和上面重叠了。
  • headerPressColorAndroid:安卓独有的设置颜色纹理,需要安卓版本大于5.0
  • gesturesEnabled:是否支持滑动返回收拾,iOS默认支持,安卓默认关闭
  • @H_404_124@

    导航视觉效果

    mode:定义跳转风格。

    • card:使用iOS和安卓默认的风格。
    • modal:iOS独有的使屏幕从底部画出。类似iOS的present效果
    • @H_404_124@

      headerMode:边缘滑动返回上级页面时动画效果

      • float:iOS默认的效果,可以看到一个明显的过渡动画。
      • screen:滑动过程中,整个页面都会返回。
      • none:没有动画。
      • @H_404_124@

        cardStyle自定义设置跳转效果

        transitionConfig自定义设置滑动返回的配置。
        onTransitionStart:当转换动画即将开始时被调用功能
        onTransitionEnd:当转换动画完成,将被调用功能

        path:路由中设置的路径的覆盖映射配置。
        initialRouteName:设置默认的页面组件,必须是上面已注册页面组件。
        initialRouteParams:初始路由的参数。

        path:path属性适用于其他app或浏览器使用url打开本app并进入指定页面。path属性用于声明一个界面路径,例如:【/pages/Home】。此时我们可以在手机浏览器中输入:app名称://pages/Home来启动该App,并进入Home界面。

        TabNavigator 基础用法/属性介绍

        const MyTab = TabNavigator({
            ShiTu: {
                screen: ShiTu,navigationOptions:{
                    tabBarLabel: '识兔',tabBarIcon: ({tintColor}) => (
                        <Image
                            source={{uri : '识兔'}}
                            style={[tabBarIcon,{tintColor: tintColor}]}
                        />
                    ),{
            tabBarPosition: 'bottom',swipeEnabled:false,animationEnabled:false,tabBarOptions: {
                style: {
                    height:49
                },activeBackgroundColor:'white',activeTintColor:'#4ECBFC',inactiveBackgroundColor:'white',inactiveTintColor:'#aaa',showLabel:false,}
        });

        屏幕导航配置

        screen:和导航的功能是一样的,对应界面名称,可以在其他页面通过这个screen传值和跳转
        navigationOptions:配置TabNavigator的一些属性

        • title标题,会同时设置导航条和标签栏的title,还是不推荐这种方式。
        • tabBarVisible:是否隐藏标签栏。默认不隐藏(true)
        • tabBarIcon:设置标签栏的图标。需要给每个都设置。
        • tabBarLabel:设置标签栏的title。推荐这个方式。
        • @H_404_124@

          标签栏配置

          tabBarPosition:设置tabbar的位置,iOS默认在底部,安卓默认在顶部。(属性值:'top','bottom')
          swipeEnabled:是否允许在标签之间进行滑动。
          animationEnabled:是否在更改标签显示动画。
          lazy:是否根据需要懒惰呈现标签,而不是提前制作,意思是在app打开的时候将底部标签栏全部加载,默认false,推荐改成true哦。
          initialRouteName: 设置默认的页面组件
          backBehavior:按 back 键是否跳转到第一个Tab(首页), none 为不跳转

          tabBarOptions:配置标签栏的一些属性

          iOS属性
          • activeTintColor:label和icon的前景色 活跃状态下(选中)。
          • activeBackgroundColor:label和icon的背景色 活跃状态下(选中) 。
          • inactiveTintColor:label和icon的前景色 不活跃状态下(未选中)。
          • inactiveBackgroundColor:label和icon的背景色 不活跃状态下(未选中)。
          • showLabel:是否显示label,默认开启。
          • style:tabbar的样式。
          • labelStyle:label的样式。
          • @H_404_124@
            安卓属性
            • 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:图标的样式。
              ps:很多人问我,为什么安卓上的tabbar文字会下移,是因为安卓比iOS多了一个属性,就是iconStyle,通过设置labelStyleiconStyle两个样式,外加style的高度,来使效果更佳合理.

              跳转

            • @H_404_124@
              navigate('Detail',{
                                 title:'图片详情',url:item.url,});

              Detail:在StackNavigator中注册页面,需要一一对应,才能跳转到相应的页面
              title:在跳转页面可以通过this.props.navigation.state.params.title获取到这个参数。当然这个参数可以随便填写,都可以通过this.props.navigation.state.params.xxx获取

              回调传参

              navigate('Detail',{
                                 // 跳转的时候携带一个参数去下个页面
                                 callback: (data)=>{
                                       console.log(data); // 打印值为:'回调参数'
                                   }
                                 });
              const {navigate,goBack,state} = this.props.navigation;
              // 在第二个页面,在goBack之前,将上个页面方法取到,并回传参数,这样回传的参数会重走render方法
              state.params.callback('回调参数');
              goBack();

              自定义

              项目中基本是没可能用自带的那个导航条的,自带导航条左侧的按钮永远是蓝色的,如果我们需要更改按钮颜色,就需要用到自定义功能了。

              const StackOptions = ({navigation}) => {
                  console.log(navigation);
                  let {state,goBack} = navigation;
              
                  // 用来判断是否隐藏或显示header
                  const visible= state.params.isVisible;
                  let header;
                  if (visible === true){
                      header = null;
                  }
                  const headerStyle = {backgroundColor:'#4ECBFC'};
                  const headerTitle = state.params.title;
                  const headerTitleStyle = {fontSize:FONT_SIZE(20),color:'white',fontWeight:'500'}
                  const headerBackTitle = false;
                  const headerLeft = (
                      <Button
                          isCustom={true}
                          customView={
                                          <Icon
                                              name='ios-arrow-back'
                                              size={30}
                                              color='white'
                                              style={{marginLeft:13}}
                                          />
                                      }
                          onPress={()=>{goBack()}}
                      />
                  );
                  return {headerStyle,headerTitle,headerTitleStyle,headerBackTitle,headerLeft,header}
              };

              然后通过下面的方法调用就可以自定制导航了。

              const MyApp = StackNavigator({
                  MyTab: {
                      screen: MyTab,navigationOptions: ({navigation}) => StackOptions({navigation})
                  },)};

              页面中使用的时候,在@R_545_404@面的时候需要传递title参数,才能看到效果哦。

              自定义tabbar

              早上有人问我,tabbar的图标可不可以使用原图,选中状态下可不可以设置其他图标。研究了一下官方文档,发现tabBarIcon除了tintColor还有另一个属性,用来判断选中状态的focused

              tabBarIcon: ({tintColor,focused}) => (
                              focused
                                  ?
                                  <Image
                                      source={{uri : '识兔'}}
                                      style={tabBarIcon}
                                  />
                                  :
                                  <Image
                                      source={{uri : '干货'}}
                                      style={[tabBarIcon,{tintColor: tintColor}]}
                                  />
                          ),

              通过判断focused,选中状态下使用识兔图标,未选中状态使用干货图标。
              如果想使用图标原来的样子,那就将styletintColor去掉,这样就会显示图标原本的颜色。

              再封装

              export const TabOptions = (tabBarTitle,normalImage,selectedImage,navTitle) => {
                  // console.log(navigation);
                  const tabBarLabel = tabBarTitle;
                  console.log(navTitle);
                  const tabBarIcon = (({tintColor,focused})=> {
                      return(
                          focused
                              ?
                              <Image
                                  source={{uri : normalImage}}
                                  style={[TabBarIcon,{tintColor: tintColor}]}
                              />
                              :
                              <Image
                                  source={{uri : selectedImage}}
                                  style={[TabBarIcon,{tintColor: tintColor}]}
                              />
                      )
                  });
                  const headerTitle = navTitle;
                  const headerTitleStyle = {fontSize:FONT_SIZE(20),color:'white'};
                  // header的style
                  const headerStyle = {backgroundColor:'#4ECBFC'};
                  return {tabBarLabel,tabBarIcon,headerStyle};
              };

              在static中使用this方法

              我之前文章中是将navaigationOptions方法写在了app.js中,没有在页面中通过static navaigationOptions来初始化页面,这段时间刚好有人问,所以在这里就写一下该怎么弄。

              首先需要在componentDidMount(){}中动态的添加点击事件
              属性给params
              componentDidMount(){
              
                  this.props.navigation.setParams({
                      title:'自定义Header',navigatePress:this.navigatePress
                  })
              }
              navigatePress = () => {
                  alert('点击headerRight');
                  console.log(this.props.navigation);
              }
              接下来就可以通过params方法获取点击事件了
              static navigationOptions = ({ navigation,screenProps }) => ({
                      title: navigation.state.params.title,headerRight:(
                          <Text onPress={navigation.state.params.navigatePress}>
                              返回
                          </Text>
                      )
              });

              让安卓实现push动画

              之前我群里的讨论怎么让安卓实现类似iOS的push动画,后来翻看官方issues的时候,真的发现了实现push动画的代码,在这里共享下

              // 先引入这个方法
              import CardStackStyleInterpolator from 'react-navigation/src/views/CardStackStyleInterpolator';
              
              // 在StackNavigator配置headerMode的地方,使用transitionConfig添加
              {
                  headerMode: 'screen',transitionConfig:()=>({
                      screenInterpolator:CardStackStyleInterpolator.forHorizontal,})
              }

              关于goBack返回指定页面

              react-navigation是提供了goBack()到指定页面方法的,那就是在goBack()中添加一个参数,但当你使用goBack('Main')的时候,你会发现并没有跳转,原因是react-navigation默认goBack()中的参数是系统随机分配的key,而不是手动设置的routeName,而方法内部又没有提供可以获得key方法,所以这里只能通过修改源码将key换成routeName了。
              下面的内容直接引用了hello老文内容

              把项目/node_modules/react-navigation/src/routers/StackRouter.js文件里的 
              const backRoute = state.routes.find((route: *) => route.key === action.key); 
              改成 const backRoute = state.routes.find(route => route.routeName === action.key);
              
              但不是很完美,这里的component要填想返回的组件的前一个组件的routeName,比如你的栈里顺序是home1,home2,home3,home4,在home4里要返回home2,使用this.props.navigation.goBack('home3');; 并且又会带出一个问题: goBack()方法没反应了,必须加个null进去,写成goBack(null)...

              关于goBack返回指定页面修改完善版

              if (action.type === NavigationActions.BACK) {
                  let backRouteIndex = null;
                  if (action.key) {
              
                    const backRoute = state.routes.find(
                      /* $FlowFixMe */
                      /* 修改源码 */
                      route => route.routeName === action.key
                      /* (route: *) => route.key === action.key */
                    );
                    /* $FlowFixMe */
                    console.log('backRoute =====',backRoute);
                    backRouteIndex = state.routes.indexOf(backRoute);
                    console.log('backRoute =====',backRouteIndex);
                  }
                  if (backRouteIndex == null) {
                    return StateUtils.pop(state);
                  }
                  if (backRouteIndex >= 0) {
                    return {
                      ...state,routes: state.routes.slice(0,backRouteIndex+1),index: backRouteIndex - 1 + 1,};
                  }
                }

              感谢群友conan的贡献,将源码改成上面的样子,就可以使用goBack()返回指定页面了,这样的优点不言而喻,但缺点就是每次调用goBack(),如果只是简单的返回上一页需要加上null参数,类似这样goBack(null)

              如果这样做,如果项目中使用了Redux,在滑动返回的时候,会有很大几率让项目卡死,请注意使用该方法

              关于快速点击会导致多次跳转的问题解决办法

              感谢群友编程大叔的贡献,如果想解决快速点击跳转的问题,需要修改部分源码。

              修改react-navigation目录下,scr文件夹中的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,};
              }

              安卓上,使用TextInput的时候会让TabBar顶起来的解决办法

              最简单的解决办法就是在android目录中,添加一句话

              目录:android/app/src/main/AndroidManifest.xml中,添加

              android:windowSoftInputMode="stateAlwaysHidden|adjustPan|adjustResize"

              ps:在iOS下如果想一劳永逸的解决键盘问题,请使用IQKeyBoardManager

              总结

              react-navigation才开始用的时候感觉是复杂的,但用的多了,会感觉真的很不错。 如果在文章中有什么不懂的问题,欢迎在评论评论,也可以发私信,加QQ群397885169一起讨论哦

作者:挂着铃铛的兔 链接:http://www.jianshu.com/p/2f575cc35780 來源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你在找的React相关文章