一冬阳、實(shí)現(xiàn)Android返回鍵點(diǎn)擊兩次退出應(yīng)用
從網(wǎng)上找到一段代碼喊衫,如下:
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('再點(diǎn)擊一次退出應(yīng)用',ToastAndroid.SHORT);
return true;
}
經(jīng)測(cè)試發(fā)現(xiàn)這段代碼并不是十分正確,因?yàn)椴徽撛谀膫€(gè)界面埠胖,我們點(diǎn)擊返回鍵都會(huì)提示“再點(diǎn)擊一次退出應(yīng)用”糠溜,而我們想要的效果是如果界面不是根界面淳玩,點(diǎn)擊返回按鈕,返回上一頁(yè)非竿;如果是根界面蜕着,點(diǎn)擊提示“再點(diǎn)擊一次退出應(yīng)用”,再次點(diǎn)擊退出應(yīng)用红柱。
那怎么判斷它是不是根界面呢承匣?又在哪里判斷呢?
我們發(fā)現(xiàn)在onBackAndroid方法中是不能通過(guò)this.props.navigation拿到navigation的锤悄,但是在navigation中有一個(gè)onNavigationStateChange方法韧骗,可以得到導(dǎo)航狀態(tài)的改變,打印log如下:
其中:prevNav是之前導(dǎo)航狀態(tài)零聚,nav是當(dāng)前導(dǎo)航狀態(tài)袍暴,action是當(dāng)前進(jìn)行的操作。所以我們可以通過(guò)當(dāng)前導(dǎo)航的狀態(tài)中的routes來(lái)判斷當(dāng)前界面是否為根界面隶症,代碼如下:
/**
* 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('再點(diǎn)擊一次退出應(yīng)用');
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政模,即在頂層組件上調(diào)用導(dǎo)航,在同一級(jí)別的Navigation screen之間使用Navigator蚂会,可以使用react的ref選項(xiàng):
/**
* 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('再點(diǎn)擊一次退出應(yīng)用');
return true;
}
render() {
return (
<AppNavigator
ref={nav => { this.navigator = nav; }}
}}/>
);
}
注:這個(gè)解決辦法只能用在頂層navigator上~
這樣淋样,就實(shí)現(xiàn)了我們想要的效果~
二、快速點(diǎn)擊多次跳轉(zhuǎn)界面問(wèn)題
當(dāng)我們快速點(diǎn)擊跳轉(zhuǎn)時(shí)胁住,會(huì)開(kāi)啟多個(gè)重復(fù)的界面趁猴,如何解決呢?
解決這個(gè)問(wèn)題需要修改react-navigation源碼彪见,詳細(xì)見(jiàn)問(wèn)題Prevent navigating twice when tapping too fast儡司,找到scr文件夾中的addNavigationHelpers.js文件,替換為如下文本即可:
export default function<S: *>(navigation: NavigationProp<S, NavigationAction>) {
// 添加點(diǎn)擊判斷
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,
}),
),
};
}