一、实现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 (
<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,
}),
),
};
}
网友评论