Posterior a de una prolongada recopilación de información hemos podido resolver esta dificultad que suelen tener ciertos de nuestros usuarios. Te dejamos la respuesta y nuestro objetivo es que te resulte de gran ayuda.
Solución:
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
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 (
container box
press back again to exit the app
BackHandler.exitApp()
>
Exit
);
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
;
Ejecutar en snack.expo: https://snack.expo.io/HyhD657d7
Lo resolví de esta manera como Componente funcional separado. De esta manera, no es necesario que vuelva a codificarlo para cada aplicación, solo incluya el componente en su nueva aplicación y ¡ya está!
import * as React from 'react';
import useEffect, useState from 'react';
import Platform, BackHandler, ToastAndroid from 'react-native';
export const ExecuteOnlyOnAndroid = (props) =>
const message = props;
const [exitApp, setExitApp] = useState(0);
const backAction = () =>
setTimeout(() =>
setExitApp(0);
, 2000); // 2 seconds to tap second-time
if (exitApp === 0)
setExitApp(exitApp + 1);
ToastAndroid.show(message, ToastAndroid.SHORT);
else if (exitApp === 1)
BackHandler.exitApp();
return true;
;
useEffect(() =>
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
backAction,
);
return () => backHandler.remove();
);
return <>>;
;
export default function DoubleTapToClose(props)
const message = 'tap back again to exit the App' = props;
return Platform.OS !== 'ios' ? (
) : (
<>>
);
=> Lo único que necesita es incluir este componente en su aplicación. <=
Debido a que IOS no tiene un botón de retroceso, IOS no necesita esta funcionalidad. El componente anterior detecta automáticamente si el dispositivo es Android o no.
De forma predeterminada, el mensaje que se muestra en Toast está predefinido en inglés, pero puede configurar uno propio si agrega una propiedad llamada message
a su DoubleTapToClose-Component.
...
import DoubleTapToClose from '../lib/android_doubleTapToClose';
...
return(
<>
...other Stuff goes here
>
Dependiendo de su estructura de navegación, debe verificar si se encuentra en una pantalla inicial de su aplicación o no. En mi caso, tengo un Cajón con múltiples StackNavigatiors en su interior. Entonces verifico si la pantalla actual es una pantalla inicial (índice: 0), o no. Si es así, configuro una variable de gancho que solo se usará para esas pantallas iniciales.
Se ve como esto:
const isCurrentScreenInitialOne = (state) =>
const route = state.routes[state.index];
if (route.state)
// Dive into nested navigators
return isCurrentScreenInitialOne(route.state);
return state.index === 0;
;
...
...
export default function App() {
...
const [isInitialScreen, setIsInitialScreen] = useState(true);
isInitialScreen && ( )
...
...
setIsInitialScreen(isCurrentScreenInitialOne(state));
>
Si esa descripción te ayuda, no te pierdas de votar.
Un mejor enfoque sería simplemente usar BackHandler y ToastAndroid
import BackHandler, ToastAndroid from 'react-native';
//rest of imports
class SomeClass extends Component
constructor(state, props)
super(state, props)
this.state =
validCloseWindow: false
async componentDidMount()
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton.bind(this));
componentWillUnmount()
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton.bind(this));
handleBackButton = () =>
if (!this.props.navigation.canGoBack())
if (this.state.validCloseWindow)
return false;
this.state.validCloseWindow = true
setTimeout(() =>
this.state.validCloseWindow = false
, 3000);
ToastAndroid.show("Press Again To Exit !", ToastAndroid.SHORT);
return true;
;
//rest of component code
Solo asegúrese de usarlo en la página de ruta inicial para su navegación.
Si posees alguna desconfianza o capacidad de ascender nuestro crónica eres capaz de dejar una crítica y con deseo lo estudiaremos.