私は、ユーザーを制限し、ネイティブの反応でワンクリックでアプリケーションから抜け出さないソリューションを探していました。
import React, {Component} from 'react';
import {BackHandler, View, Dimensions, Animated, TouchableOpacity, Text} from 'react-native';
let {width, height} = Dimensions.get('window');
export default class App extends Component<Props> {
state = {
backClickCount: 0
};
constructor(props) {
super(props);
this.springValue = new Animated.Value(100);
}
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton.bind(this));
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton.bind(this));
}
_spring() {
this.setState({backClickCount: 1}, () => {
Animated.sequence([
Animated.spring(
this.springValue,
{
toValue: -.15 * height,
friction: 5,
duration: 300,
useNativeDriver: true,
}
),
Animated.timing(
this.springValue,
{
toValue: 100,
duration: 300,
useNativeDriver: true,
}
),
]).start(() => {
this.setState({backClickCount: 0});
});
});
}
handleBackButton = () => {
this.state.backClickCount == 1 ? BackHandler.exitApp() : this._spring();
return true;
};
render() {
return (
<View style={styles.container}>
<Text>
container box
</Text>
<Animated.View style={[styles.animatedView, {transform: [{translateY: this.springValue}]}]}>
<Text style={styles.exitTitleText}>press back again to exit the app</Text>
<TouchableOpacity
activeOpacity={0.9}
onPress={() => BackHandler.exitApp()}
>
<Text style={styles.exitText}>Exit</Text>
</TouchableOpacity>
</Animated.View>
</View>
);
}
}
const styles = {
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
},
animatedView: {
width,
backgroundColor: "#0a5386",
elevation: 2,
position: "absolute",
bottom: 0,
padding: 10,
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
},
exitTitleText: {
textAlign: "center",
color: "#ffffff",
marginRight: 10,
},
exitText: {
color: "#e5933a",
paddingHorizontal: 10,
paddingVertical: 3
}
};
Snack.expoで実行: https://snack.expo.io/HyhD657d7
以下のコードはそれ自体を説明しています。トリックは、Main AppContainerではなくすべてのページ
import { Alert, BackHandler, ToastAndroid } from 'react-native';
import { StackActions } from 'react-navigation';
// common statless class variable.
let backHandlerClickCount = 0;
class App extends React.Component {
constructor(props) {
super(props);
// add listener to didFocus
this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
BackHandler.addEventListener('hardwareBackPress', () => this.onBackButtonPressAndroid(payload)));
}
// remove listener on unmount
componentWillUnmount() {
if (this._didFocusSubscription) {
this._didFocusSubscription.remove();
}
}
onBackButtonPressAndroid = () => {
const shortToast = message => {
ToastAndroid.showWithGravityAndOffset(
message,
ToastAndroid.SHORT,
ToastAndroid.BOTTOM,
25,
50
);
const {
clickedPosition
} = this.state;
backHandlerClickCount += 1;
if ((clickedPosition !== 1)) {
if ((backHandlerClickCount < 2)) {
shortToast('Press again to quit the application!');
} else {
BackHandler.exitApp();
}
}
// timeout for fade and exit
setTimeout(() => {
backHandlerClickCount = 0;
}, 2000);
if (((clickedPosition === 1) &&
(this.props.navigation.isFocused()))) {
Alert.alert(
'Exit Application',
'Do you want to quit application?', [{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
}, {
text: 'OK',
onPress: () => BackHandler.exitApp()
}], {
cancelable: false
}
);
} else {
this.props.navigation.dispatch(StackActions.pop({
n: 1
}));
}
return true;
}
}