使用react-navigation详解(四)--功能优化

一、实现Android返回键点击两次退出应用

从网上找到一段代码,如下:

componentWillMount(){  
    BackHandler.addEventListener('hardwareBackPress', this._onBackAndroid );  
}  
  
  
componentUnWillMount(){  
    BackHandler.addEventListener('hardwareBackPress', this._onBackAndroid);  
}  
  
_onBackAndroid=()=>{  
    let now = new Date().getTime();  
    if(now - lastBackPressed < 2500) {  
        return false;  
    }  
    lastBackPressed = now;  
    ToastAndroid.show('再点击一次退出应用',ToastAndroid.SHORT);  
    return true;  
}  

经测试发现这段代码并不是十分正确,因为不论在哪个界面,我们点击返回键都会提示“再点击一次退出应用”,而我们想要的效果是如果界面不是根界面,点击返回按钮,返回上一页;如果是根界面,点击提示“再点击一次退出应用”,再次点击退出应用。
那怎么判断它是不是根界面呢?又在哪里判断呢?
我们发现在onBackAndroid方法中是不能通过this.props.navigation拿到navigation的,但是在navigation中有一个onNavigationStateChange方法,可以得到导航状态的改变,打印log如下:

其中:prevNav是之前导航状态,nav是当前导航状态,action是当前进行的操作。所以我们可以通过当前导航的状态中的routes来判断当前界面是否为根界面,代码如下:

/**
 * Created by sybil052 on 2017/8/18.
 */
...
let routes = [];
let lastBackPressed = null;
...
    componentDidMount() {
        BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid);
    }


    componentWillUnmount() {
        BackHandler.removeEventListener('hardwareBackPress', this.onBackAndroid);
        lastBackPressed = null;
    }

    onBackAndroid() {
        if (routes.length === 1) { // 根界面
            if (lastBackPressed && lastBackPressed + 2000 >= Date.now()) {
                return false;
            }
            lastBackPressed = Date.now();
            Toast.showShortCenter('再点击一次退出应用');
            return true;
        }
    }
    render() {
        return (
             {
                console.log('prevNav=',prevNav);
                console.log('nav=',nav);
                console.log('action=',action);
                routes = nav.routes;
            }}/>
        );
    }

还有一种方法可以在onBackAndroid()方法中拿到navigation,即在顶层组件上调用导航,在同一级别的Navigation screen之间使用Navigator,可以使用react的ref选项:

/**
 * Created by sybil052 on 2017/8/28.
 */
...
let lastBackPressed = null;
...
    componentDidMount() {
        BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid);
    }

    componentWillUnmount() {
        BackHandler.removeEventListener('hardwareBackPress', this.onBackAndroid);
        lastBackPressed = null;
    }

    onBackAndroid() {
        if(this.navigator._navigation.state.routes.length > 1) {
            this.navigator._navigation.goBack();
            return true;
        }
        if (lastBackPressed && lastBackPressed + 2000 >= Date.now()) {
            return false;
        }
        lastBackPressed = Date.now();
        Toast.showShortCenter('再点击一次退出应用');
        return true;
    }
    render() {
        return (
             { this.navigator = nav; }}
            }}/>
        );
    }

注:这个解决办法只能用在顶层navigator上~

这样,就实现了我们想要的效果~

二、快速点击多次跳转界面问题

当我们快速点击跳转时,会开启多个重复的界面,如何解决呢?

解决这个问题需要修改react-navigation源码,详细见问题Prevent navigating twice when tapping too fast,找到scr文件夹中的addNavigationHelpers.js文件,替换为如下文本即可:

export default function(navigation: NavigationProp) {  
  // 添加点击判断  
  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,  
        }),  
      ),  
  };  
}  

你可能感兴趣的:(使用react-navigation详解(四)--功能优化)