react-navigation升級3.x 問題解決方案

時間請你忘記我發表於2019-03-26

背景

  • 最近把之前的RN專案更新了,react-native升級到了0.58,react-navigation升級到了3.3.0。
  • 我們專案結構是TabNavigation,有A/B/C三個Tab,根據使用者的許可權來決定展示幾個Tab,會有四種情況,ABC、AC、BC、C(C是一直存在的)。用createAppContainer建立了四個TabNavigation

升級

  • 按照舊版本的實現,建立三個StackNavigator,按照許可權再建立四個TabNavigator,根據許可權來決定展示哪個。新版本升級後,統一使用createXXXNavigator生成,然後通過createAppContainer匯出才行。

遇到的問題

  • 修改為新版本的寫法後,發現進入二級頁面tabbar不隱藏了,之前的引數不管用了。查閱文件後,官方給出了建議的寫法:把TabNavigator當做StackNavigator的一部分,push時二級頁面整個蓋到TabNavigator上。reactnavigation.org/docs/en/nav…
  • 之前跳轉二級頁面時寫的是this.props.navigation.navigate('XXX'),按照上面官方建議修改之後發現不好使了…原因是this.props.navigation獲取到的是當前頁面的navigation,但是我們外面包了一層TabNavigator,此時應該用TabNavigator的navigation去navigate('XXX')。比如頁面A和頁面B,在TabC上,在頁面A上navigate('D'),但是頁面A的StackNavigator裡沒有D哇,並且我們要把Tab蓋住哇,所以要用TabC的this.props.navigation去navigate('D')才可以。如果頁面A的StackNavigator裡有D,navigate時tabbar還會在,隱藏不了,就又回到了上一個問題。我的解決辦法是:在跳轉二級頁面時發個通知,用TabC接收,然後再TabC裡進行頁面跳轉。有點笨,但是想不到其它好辦法了…
  • 還有就是安卓物理返回鍵的問題。這個問題真的很尷尬啊,在第一個Tab進二級頁面,按返回鍵可以很棒的返回,然而在第二個和第三個Tab進二級頁面後,按一下返回沒反應,按兩下就直接到第一個Tab了!!!Oh my god~~~~然後找解決方案,官方文件給出了reactnavigation.org/docs/en/cus…,我是想在一個地方寫然後全域性都可用,來來回試了很多次也沒弄好,只能每個頁面都寫了一次,具體實現看下面的程式碼。

具體實現

  1. 我們專案結構是TabNavigation,有A/B/C三個Tab,根據使用者的許可權來決定展示幾個Tab,會有四種情況,ABC、AC、BC、C(C是一直存在的)。用createAppContainer建立了四個TabNavigation
const ABCTabbar = createBottomTabNavigator({
    'ANav': {screen: ANav,},
    'BNav': {screen: BNav,},
    'CNav': {screen: CNav,},
});
const ACTabbar = createBottomTabNavigator({
    'ANav': {screen: ANav,},
    'CNav': {screen: CNav,},
});
const BCTabbar = createBottomTabNavigator({
    'BNav': {screen: BNav,},
    'CNav': {screen: CNav,},
});
const CTabbar = createBottomTabNavigator({
    'CNav': {screen: CNav,},
});

const ABCTabNavigator = createAppContainer(ABCTabbar);
const ACTabNavigator = createAppContainer(ACTabbar);
const BCTabNavigator = createAppContainer(BCTabbar);
const CTabNavigator = createAppContainer(CTabbar);
export { ABCTabNavigator, ACTabNavigator, BCTabNavigator, CTabNavigator };
複製程式碼
  1. 新建MainNavigation.js,在這個檔案裡判斷使用者有哪些許可權,然後展示相應的TabNavigator
class MainNav extends Component {
	render() {
	  if (this.state.permission === 'ABC') {
	    return (<ABCTabNavigator/>);
	  } else if (this.state.permission == 'AC') {
	    return (<ACTabNavigator/>);
	  } else if (this.state.permission == 'BC') {
	    return (<BCTabNavigator/>);
	  } else {
	    return (<CTabNavigator/>);
	  }
	}
}
複製程式碼
  1. 在MainNavigation.js裡,生成一個MainNavigation,在入口render裡配置成就OK了
const Main = createStackNavigator({
    MainNav: {screen: MainNav},
    DPage: {screen: DPage},
});
const MainNavigation = createAppContainer(Main);
export default MainNavigation;
複製程式碼
  1. 安卓物理返回鍵問題。從網上找了個工具類AndroidBackAction.js,修改了一下
import {BackHandler} from 'react-native';

const handleAndroidBackButton = callback => {
  BackHandler.addEventListener('hardwareBackPress', callback);
};

const removeAndroidBackButtonHandler = (callback) => {
  BackHandler.removeEventListener('hardwareBackPress', callback);
}

export {handleAndroidBackButton, removeAndroidBackButtonHandler};
複製程式碼

頁面上的實現:

import {handleAndroidBackButton, removeAndroidBackButtonHandler} from '../../Util/AndroidBackAction.js'; 	// 你自己的路徑

export default class D extends Component {

    constructor(props) {
        super(props);
        handleAndroidBackButton(this.onBackAndroid);	// 一定要在這裡寫
    }

    componentWillUnmount() {
        removeAndroidBackButtonHandler(this.onBackAndroid);	// 一定要在這裡寫
    }

    onBackAndroid = () => {
        this.props.navigation.goBack();
        return true;
    };
}

複製程式碼

還有個按兩下退出應用的,我是寫在了入口的地方(就配置的地方),監聽的方式是一樣的,就是onBackAndroid實現不一樣

onBackAndroid = () => {
    if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
        //最近2秒內按過back鍵,可以退出應用。
        return false;
    }
    this.lastBackPressed = Date.now();
    ToastAndroid.show('再按返回退出應用', ToastAndroid.SHORT);
    return true;
};
複製程式碼

好啦,大功告成~~~

結束~撒花~~~

相關文章