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

之前写过react-navigation使用技巧,那篇文章中主要讲了react-navigation的属性,封装和一些小技巧。虽然上篇文章中也有一些小技巧,但因为补充的比较晚,导致有些人没有看全,再加上我又找到了一些新的小玩意,特此写了本篇文章,如果之后还有新发现,也会再这篇文章中更新出来。

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

1、让TabBar拥有点击事件

react-navigationbeta13版本之后,已经默认支持点击事件了,它被放在了TabNavigator中,属性名为tabBarOnPress,内部提供了两个属性,一个方法({ route, index } , jumpToIndex),使用方法如下:

tabBarOnPress:(obj)=>{
            console.log(obj);

            obj.jumpToIndex(obj.scene.index)
        },

最新几个版本的react-navigation中,将代码和文件路径修改了,所以之前的方式失效了,在这里提供一个新的方法来修改Tabbar的点击事件。
#### 原文链接

一共要修改添加大大小小12处地方哦!涉及4个js文件。 这个修改已经被作者提交到react-navigation中了,希望在以后的更新中可以看到这次更新。

使用方法

static navigationOptions = ({navigation,screenProps}) => ({
    headerTitle:'首页',
    tabBarOnPress: (scene,jumpToIndex) => {
         console.log(scene); 
         jumpToIndex(scene.index)
    },
});

~~ 注意:如果调用了tabBarOnPress方法,会默认关闭点击跳转事件,需要手动开启。!~~

以下代码已被废弃

感谢群友再遇见的分享。

官方的api里面是没有提供tabBar的点击事件的,但在开发中经常需要监听tabBar的点击事件,解决这个问题的一种方法就是去修改源码,另一种是监听onTransitionEnd。(第二种方法这里先不讨论)

源码中一共需要修改8处地方,包含3个js文件。源码在下面。

1、react-navigation目录下src/views/TabView/TabBarBottom.js

TabBarBottom.png

2、react-navigation目录下src/views/TabView/TabBarTop.js

TabBarTop.png

3、react-navigation目录下src/views/TabView/TabView.js

TabView.png

#### 注意:第111行中的getScreenConfig需要手动改成getScreenOptions,要不然修改完源码会报错。

#### 源码在这里,要注意修改getScreenOptions

修改源码之后,在页面中这么用:

static navigationOptions = ({navigation,screenProps}) => ({
    onTabPress:(()=>{
        alert('Home');
    })
});

2、修改页面的跳转动画

在上一篇文章中,说了怎么将安卓的跳转动画改成iOS那样的,但其实react-navigation一共提供了4种跳转动画:
1、从右向左: forHorizontal
2、从下向上: forVertical
3、安卓那种的从下向上: forFadeFromBottomAndroid
4、无动画: forInitial

但因为库的限制,想实现某些页面使用某种动画还是很难的,只能通过Demo中提供的笨方法来实现。

首先还是导入react-navigation中的方法


import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator';

2.0
import StackViewStyleInterpolator from 'react-navigation/src/views/StackView/StackViewStyleInterpolator';

如果要改变跳转动画只能在StackNavigator中实现transitionConfig方法

const MainStack = StackNavigator({
    Main:{
        screen:Main,
    },
},{
    // mode:'modal',
    headerMode: 'screen',
    transitionConfig:()=>({
     // 只要修改最后的forVertical就可以实现不同的动画了。
      screenInterpolator:CardStackStyleInterpolator.forVertical,
    })
});

3、在Reset方法中传参

react-navigation中的reset方法,应该都不陌生吧,重置路由。但有的需求是在登陆之后,重置路由并传递参数到某个页面,之前一直以为不可以,直到群友的react-native reset方法中传参的写法的这篇文章出现,感谢群友nextChampion的贡献。

const resetAction = NavigationActions.reset({
    index: 0,
    actions: [
    NavigationActions.navigate({routeName: 'Home', params: { token: '123456' }})
    ]
})

this.props.navigation.dispatch(resetAction);

在页面中可以通过如下方法得到参数。

this.props.navigation.state.params.token 

4、goBack返回指定页面

在上篇文章中也有这个技巧,这里是总结重发。

react-navigation目录下src/routers/StackRouter.js

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,
      };
    }
  }

注意:这样的修改源码之后,如果项目中使用Redux,并且启用了滑动返回,很会很大几率导致app卡死,所以并不太推荐这种方式,最好使用下面的方式

5、react-navigation集成Redux

可能会有人认为这样集成会麻烦,而且react-navigation内部实现也是类似Redux的高阶函数。我之前也是这么认为的,直到在识兔中,使用 Redux 修改首页图片之后 滑动返回 会导致app卡死。

react-navigation集成Redux之后,能获取当前screenkeyrouteNmae等参数,goBack()的时候就可以直接取到key,而不用修改源码啦!

具体操作步骤可以在识兔,一款用来识别图片的开源项目中查看。

如果看不懂下面的修改步骤,可以先看下之前的文章Redux "使用"教程

集成

1、添加addNavigationHelpers

import {
    StackNavigator,
    TabNavigator,
    addNavigationHelpers
} from 'react-navigation';

2、首先修改识兔中的App.js的导出方式

const AppWithNavigationState = ({ dispatch, nav }) => (
    <MyApp navigation={addNavigationHelpers({ dispatch, state: nav })}/>
);

const mapStateToProps = state => ({
    nav: state.nav,
});

export default connect(mapStateToProps)(AppWithNavigationState);

3、创建StackReducer

// MyApp 是在App.js中导出的
import { MyApp } from '../APP';


export default function StackReducer(state , action) {
    let nextState;
    switch (action.type) {
        default:
            nextState = MyApp.router.getStateForAction(action, state);
            break;
    }
    return nextState || state;
}

4、修改rootReducer

import nav from './StackReducer';

const RootReducer = combineReducers({
    ...,
    nav,
});

export default RootReducer;

使用

1、修改ShiTu.js

export default connect((state) => {
    ...
    const routes  = state.nav.routes;
    return {
        ...
        routes
    };
},{...})(ShiTu)

2、使用

const {routes} = this.props;
// 会有意想不到的惊喜哦!
console.log(routes);

感谢群友Roc的提供的react-navigation集成redux的 脚手架 可以通过它快速实现集成Redux

6、安卓返回键在react-navigation中的正常监听

之前使用Navigator的时候,可以通过下面的方法实现监听安卓的返回键,但使用了react-navigation后,会很迷茫,不知该怎么监听了。

解决办法:集成Redux咯!😂😂😂 集成完Redux,在跳转之后,就能获得路由的length,可以通过length来判断当前页面是第几层。

Navigator的方法

componentWillMount() {
    if (Platform.OS === 'android') {
      BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid);
    }
  }
componentWillUnmount() {
    if (Platform.OS === 'android') {
      BackAndroid.removeEventListener('hardwareBackPress', this.onBackAndroid);
    }
  }
onBackAndroid = () => {
    const nav = this.navigator;
    const routers = nav.getCurrentRoutes();
    if (routers.length > 1) {
      nav.pop();
      return true;
    }
    return false;
  };
  ……
}

react-navigation的方式

componentWillMount() {
    if (Platform.OS === 'android') {
        BackHandler.addEventListener('handwareBackPress',this.onBackAndroid)
    }
  }
componentWillUnmount() {
    if (Platform.OS === 'android') {
        BackHandler.addEventListener('handwareBackPress',this.onBackAndroid)
    }
  }
onBackAndroid = () => {
    const routers = nav.getCurrentRoutes();
    if (routers.length > 1) {
      return true;
    }
    return false;
  };
  ……
}

// 在跳转之后的页面中
onBackAndroid = ()=> {

    const {routes} = this.props;
    console.log(routes);
    // alert(routes)
    if (routes.length > 1) {
        // 因为其他页面获得不到this.props,所以只能每个页面都写这个方法。
        this.props.navigation.goBack();
        return true;
    }
}

7、快速点击重复跳转的解决办法

感谢群友编程大叔的贡献

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,
        }),
      ),
  };
}

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

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

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

 android:windowSoftInputMode="stateAlwaysHidden|adjustPan|adjustResize"

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

总结

上述7个问题,是我暂时发现的可能在使用react-navigation遇到的问题,如果遇到其他问题欢迎加入QQ群397885169一起讨论,解决。

如果在文章中遇到什么错误,欢迎加群反馈,吐槽。

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

推荐阅读更多精彩内容

  • react-navigation导航组件使用详解 注意了,如果有小伙伴们发现运行作者提供的react-naviga...
    光强_上海阅读 23,439评论 38 103
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,832评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 先跟偶像饭基友在猎德吃了个饭然后再去科韵路。席间和路上吹了好多水,也确认下自己之前了解的信息有没有问题之类。 基友...
    凉风口香糖阅读 825评论 0 0
  • 日复一日,就醒来,睡去 齿轮咬紧他的兄弟 钟表边敲边叫不要靠近 今天过后是明天 看客沉沉睡去 梦里抬头是风 低头落雨
    送往劳来阅读 139评论 0 0