美文网首页React Native学习
使用react-navigation详解(四)--功能优化

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

作者: sybil052 | 来源:发表于2017-08-23 14:26 被阅读1288次

    一、实现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如下:

    WX20170823-140433@2x.png

    其中: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 (
                <AppNavigator
                    onNavigationStateChange={(prevNav, nav, action) => {
                    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 (
                <AppNavigator
                    ref={nav => { this.navigator = nav; }}
                }}/>
            );
        }
    

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

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

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

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

    解决这个问题需要修改react-navigation源码,详细见问题Prevent navigating twice when tapping too fast,找到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,  
            }),  
          ),  
      };  
    }  
    

    相关文章

      网友评论

        本文标题:使用react-navigation详解(四)--功能优化

        本文链接:https://www.haomeiwen.com/subject/jgokdxtx.html