it-swarm.com.de

React Native - Handhabung der Geräte-Rücktasten

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!

8
Virat18

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.

25
Virat18

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.

3
Ruchi

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

2
Shubham Kakkar

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!.

2
Rishav Kumar

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 /> }
}
1
Gani Siva kumar
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,
                })
            }
        />
    );
}
0
yamaha