Ich möchte prüfen, ob mehrere Bildschirme im Stapel sind, wenn die Zurück-Taste des Geräts gedrückt wird. Wenn ja, möchte ich den vorherigen Bildschirm anzeigen und wenn nein, möchte ich die App beenden.
Ich habe die Anzahl der Beispiele geprüft, diese verwenden jedoch BackAndroid und Navigator. Beide sind jedoch veraltet. BackHandler ersetzt BackAndroid. Ich kann den vorherigen Bildschirm mithilfe von props.navigation.goBack (null) anzeigen.
Ich kann jedoch keinen Code zum Auffinden der Bildschirmanzahl im Stapel finden. Ich möchte keinen veralteten Navigator verwenden!
Dieses Beispiel zeigt Ihnen eine Rückwärtsnavigation, die normalerweise in den meisten Flüssen erwartet wird. Je nach erwartetem Verhalten müssen Sie jedem Bildschirm den folgenden Code hinzufügen. Es gibt zwei Fälle: 1. Wenn sich mehr als ein Bildschirm im Stapel befindet, zeigt die Schaltfläche "Zurück" des Geräts den vorherigen Bildschirm an. 2. Wenn sich nur ein Bildschirm im Stapel befindet, wird die Zurück-Schaltfläche des Geräts beendet.
Fall 1: Vorherigen Bildschirm anzeigen
import { BackHandler } from 'react-native';
constructor(props) {
super(props)
this.handleBackButtonClick = this.handleBackButtonClick.bind(this);
}
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonClick);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButtonClick);
}
handleBackButtonClick() {
this.props.navigation.goBack(null);
return true;
}
Wichtig: Vergessen Sie nicht, die Methode im Konstruktor zu binden und den Listener in ComponentWillUnmount zu entfernen.
Fall 2: App beenden
In diesem Fall müssen Sie nichts auf dem Bildschirm behandeln, an dem Sie die App beenden möchten.
Wichtig: Dies sollte nur Bildschirm auf Stapel sein.
In einem Fall, in dem sich mehr als eine Anzeige im Stapel befindet, besteht das Standardverhalten der Rückschaltfläche in reaktionsnah darin, zum vorherigen Bildschirm im Stapel zurückzukehren. Wenn Sie die Rücktaste des Geräts betätigen, wenn Sie nur einen Bildschirm zum Beenden der App haben, ist eine benutzerdefinierte Einstellung erforderlich. Dies kann jedoch erreicht werden, ohne dass zu jedem Bildschirm ein Rückführungscode hinzugefügt werden muss, indem die getStateForAction-Methode des jeweiligen Routers von StackNavigator geändert wird.
Angenommen, Sie haben den folgenden StackNavigator in der Anwendung verwendet
const ScreenStack = StackNavigator(
{
'Screen1': {
screen: Screen1
},
'Screen2': {
screen: Screen2
},
},
{
initialRouteName: 'Screen1'
}
);
Die getStateForAction-Methode des Routers des Stack-Navigators kann wie folgt geändert werden, um das erwartete Rückverhalten zu erzielen.
const defaultStackGetStateForAction =
ScreenStack.router.getStateForAction;
ScreenStack.router.getStateForAction = (action, state) => {
if(state.index === 0 && action.type === NavigationActions.BACK){
BackHandler.exitApp();
return null;
}
return defaultStackGetStateForAction(action, state);
};
state.index
wird nur dann zu 0
, wenn sich ein Bildschirm im Stapel befindet.
versuchen Sie dies Navigation reagieren
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () => {
const pushAction = StackActions.Push({
routeName: 'DefaultSelections',
});
this.props.navigation.dispatch(pushAction);
}
aktueller Bildschirm ist "DefaultSelections", beim Drücken der Taste "Zurück" wird auf denselben Bildschirm umgeschaltet und daher die Schaltfläche "Zurück" deaktiviert
return true
für backButton (wie in den offiziellen Dokumenten vorgeschlagen) deaktiviert Schaltfläche "Zurück" auf allen Bildschirme; nicht erwünscht
Guyz, bitte verstehen Sie, es kann nicht nur das Problem sein, mit dem native reagieren. Seien Sie vorsichtig, wenn Sie es mit firebase integrieren .. Die neueste Version der firebase hat das Problem, dass die Schaltfläche "Zurück" in reaktiöse Apps integriert wird !! Bitte downgraden Sie die Firebase-Version auf die Firebase-Version @ 5.0.3 und überprüfen Sie dann erneut, ob sie funktioniert oder nicht! Ich hatte das gleiche Problem und war tagelang besorgt. Ich habe endlich auf die Version 5.0.3 heruntergestuft und der Zurück-Button funktioniert jetzt einwandfrei!.
Ich bin auf v0.46.0 von reag-native und hatte das gleiche Problem. Ich habe das Problem in dieser Datei in der Basis von Reaktiver-Node nachverfolgt
https://github.com/facebook/react-native/blob/master/Libraries/Utilities/BackHandler.Android.js#L25
Beim Laufen mit dem Chrome-Debugger ist die Leitung abgeschaltet
var subscriptions = Array.from(_backPressSubscriptions.values()).reverse()
gibt immer ein leeres Array für Subskriptionen zurück, wodurch die invokeDefault-Variable true bleibt und die .exitApp () - Funktion aufgerufen wird.
Nach weiteren Untersuchungen glaube ich, dass das Problem in den folgenden PR # 15182 entdeckt und diskutiert wurde.
Selbst nach dem Kopieren/Einfügen der PR-Änderung in einer älteren Version von RN funktionierte dies höchstwahrscheinlich nicht durch das in der PR beschriebene Problem.
Nach ein paar geringfügigen Modifikationen bekam ich es zu ändern
RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
var invokeDefault = true;
var subscriptions = []
_backPressSubscriptions.forEach(sub => subscriptions.Push(sub))
for (var i = 0; i < subscriptions.reverse().length; ++i) {
if (subscriptions[i]()) {
invokeDefault = false;
break;
}
}
if (invokeDefault) {
BackHandler.exitApp();
}
});
Verwenden Sie einfach eine .forEach-Funktion, die die ursprüngliche Implementierung in der PR war, bevor die geänderte Array.from-Syntax durchgehend funktioniert.
Sie könnten also reaktiv-native verzweigen und eine modifizierte Version verwenden, eine PR einreichen, obwohl ich mir vorstellen kann, dass dies einige Zeit dauern wird, bis sie genehmigt und im Upstream zusammengeführt wird, oder Sie können etwas Ähnliches tun, was ich getan habe (...) für das Ereignis hardwareBackPress.
// other imports
import { BackHandler, DeviceEventEmitter } from 'react-native'
class MyApp extends Component {
constructor(props) {
super(props)
this.backPressSubscriptions = new Set()
}
componentDidMount = () => {
DeviceEventEmitter.removeAllListeners('hardwareBackPress')
DeviceEventEmitter.addListener('hardwareBackPress', () => {
let invokeDefault = true
const subscriptions = []
this.backPressSubscriptions.forEach(sub => subscriptions.Push(sub))
for (let i = 0; i < subscriptions.reverse().length; i += 1) {
if (subscriptions[i]()) {
invokeDefault = false
break
}
}
if (invokeDefault) {
BackHandler.exitApp()
}
})
this.backPressSubscriptions.add(this.handleHardwareBack)
}
componentWillUnmount = () => {
DeviceEventEmitter.removeAllListeners('hardwareBackPress')
this.backPressSubscriptions.clear()
}
handleHardwareBack = () => { /* do your thing */ }
render() { return <YourApp /> }
}
constructor(props){
super(props)
this.onBackPress = this.onBackPress.bind(this);
}
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.onBackPress);
}
componentWillUnmount(){
BackHandler.removeEventListener('hardwareBackPress', this.onBackPress);
}
onBackPress(){
const {dispatch, nav} = this.props;
if (nav.index < 0) {
return false;
}
dispatch(NavigationActions.back());
return true;
}
render(){
const {dispatch, nav} = this.props;
return(
<DrawerRouter
navigation= {
addNavigationHelpers({
dispatch,
state: nav,
addListener,
})
}
/>
);
}