web-dev-qa-db-fra.com

Gestion du bouton Précédent dans React Native, Navigator sur Android

J'ai un Navigator dans une application native pour Android.

J'utilise navigator.Push() pour naviguer vers une autre page. Il semblerait naturel que le bouton Précédent ouvre le navigateur et recule d'une page, mais ce n'est pas ce qui se passe (il quitte l'application).

Navigator n'a-t-il vraiment aucun support pour le bouton Précédent? Dois-je le connecter moi-même avec un BackAndroid?

30
erwan

Oui, vous devez manipuler le bouton de retour vous-même. Je pense que la raison principale en est que vous voudrez peut-être faire différentes choses avec le bouton de retour au lieu de simplement revenir en arrière dans la pile. Cependant, je ne sais pas s'il est prévu d'intégrer la fonctionnalité du bouton arrière à l'avenir.

7
rmevans9

En plus de répondre ci-dessus, le code de traitement devrait ressembler à ceci:

var navigator; 

React.BackAndroid.addEventListener('hardwareBackPress', () => {
    if (navigator && navigator.getCurrentRoutes().length > 1) {
        navigator.pop();
        return true;
    }
    return false;
});

dans le code de rendu:

<Navigator ref={(nav) => { navigator = nav; }} />
47
kar

Vous ne savez pas quand l'API a changé, mais à partir du moment où vous réagissez en tant que version native 0.31 (également aux versions potentiellement antérieures), BackAndroid est un composant qui doit être importé de react-native:

import {..., BackAndroid} from 'react-native'

Veillez également à supprimer le programme d'écoute sur le composantWillUnmount:

componentWillUnmount(){
    BackAndroid.removeEventListener('hardwareBackPress', () => {
        if (this.navigator && this.navigator.getCurrentRoutes().length > 1) {
            this.navigator.pop();
            return true;
        }
        return false;
    });
}

* UPDATE: Dans la version native 0.44, ce module a été renommé en BackHandler. Navigator est également officiellement obsolète, mais vous pouvez toujours le trouver ici: https://github.com/facebookarchive/react-native-custom-components

import { BackHandler } from 'react-native';
14
Maxwelll

N'oubliez pas bind [this]

La bonne réponse devrait être: 

export default class MyPage extends Component {
  constructor(props) {
    super(props)
    this.navigator = null;

    this.handleBack = (() => {
      if (this.navigator && this.navigator.getCurrentRoutes().length > 1){
        this.navigator.pop();
        return true; //avoid closing the app
      }

      return false; //close the app
    }).bind(this) //don't forget bind this, you will remember anyway.
  }

  componentDidMount() {
    BackAndroid.addEventListener('hardwareBackPress', this.handleBack);
  }

  componentWillUnmount() {
    BackAndroid.removeEventListener('hardwareBackPress', this.handleBack);
  }

  render() {
    return (
      <Navigator
        ref={navigator => {this.navigator = navigator}}
  ...
6
Huiming Yuan

Afin de nettoyer le code en utilisant mes connaissances et mes réponses précédentes, voici à quoi il devrait ressembler:

import { ..., Navigator, BackAndroid } from 'react-native';

componentDidMount() {
  BackAndroid.addEventListener('hardwareBackPress', this.handleBack);
}

componentWillUnmount() {
  //Forgetting to remove the listener will cause pop executes multiple times
  BackAndroid.removeEventListener('hardwareBackPress', this.handleBack);
}

handleBack() {
  if (this.navigator && this.navigator.getCurrentRoutes().length > 1){
    this.navigator.pop();
    return true; //avoid closing the app
  }

  return false; //close the app
}
1
Facundo La Rocca

J'ai créé un dépôt GitHub qui vous fournira un exemple de projet sur la gestion du bouton Précédent Android.

Vous pouvez cloner/télécharger le dépôt sur:

Exemple de projet de bouton de retour Android

Mais voici quelques exemples de codes sur la façon dont je gère le bouton de retour Android

Le code suivant est pour mon écran initial lorsque l'utilisateur lance mon application. En appuyant sur le bouton de retour ici affichera une alerte qui demandera à l'utilisateur s'il souhaite quitter l'application.

import React, {Component} from 'react';
import {View,Text,Button,BackHandler,Alert} from 'react-native';
import {NavigationActions} from 'react-navigation';

export default class InitScreen extends Component {
    _focusDoneSubscribe;//declaring variable that will be listener for the back button when in focus 
    _blurGoingSubscribe;//declaring variable that will be listener for the back button when blur 

    //the following will remove the navigation bar at the top
    static navigationOptions = {
        header: null,
        title: 'Welcome',
    };

    constructor(props)
    {
        super(props);
        this._focusDoneSubscribe = props.navigation.addListener('didFocus', payload =>
            BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
        );//this assigns the listener
    }
    //functions to handle back button events
    componentDidMount()
    {
        this._blurGoingSubscribe = this.props.navigation.addListener('willBlur', payload =>
                BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
            );
    }

    onBackButtonPressAndroid = () => {
        Alert.alert(
            'Exiting App',
            'Confirm quitting the app?',
            [
                {text: 'CANCEL', style: 'cancel'},
                {text: 'STOP ASKING AND QUIT', onPress: () => BackHandler.exitApp()}
            ],
            {cancelable: false},
        );
        return true;
    };

    componentWillUnmount()
    {
        this._focusDoneSubscribe && this._focusDoneSubscribe.remove();
        this._blurGoingSubscribe && this._blurGoingSubscribe.remove();
    }
    //actual render
    render(){
        const { navigate } = this.props.navigation;
        return (
            <View style={{alignItems: 'center'}}>
                <View style={{height: 100,justifyContent: 'center',alignItems: 'center'}}>
                    <Text style={{fontSize: 20}}>Navigation BackHandler Tutorial</Text>
                    <Text style={{fontSize: 20}}>Initial Screen</Text>
                </View>
                <View style={{flexDirection: 'column', justifyContent: 'space-between', height: 100}}>
                    <Button
                    title="SCREEN ONE"
                    onPress={() => {this.props.navigation.Push('One')}}
                    />
                    <Button
                    title="SCREEN TWO"
                    onPress={() => {this.props.navigation.Push('Two')}}
                    />
                </View>
            </View>
        );
    }
}

Le code suivant est un écran pour lequel, lorsque l'utilisateur appuie sur le bouton Précédent, il retourne à l'écran précédent:

import React, {Component} from 'react';
import {View,Text,Button,BackHandler} from 'react-native';//declaring variable that will be listener for the back button when in focus 
import {NavigationActions} from 'react-navigation';//declaring variable that will be listener for the back button when blur 

export default class ScreenOne extends Component {
    _focusDoneSubscribe;
    _blurGoingSubscribe;

    //the following will remove the navigation bar at the top
    static navigationOptions = {
        header: null,
        title: 'ONE',
    };

    constructor(props)
    {
        super(props);
        this._focusDoneSubscribe = props.navigation.addListener('didFocus', payload =>
            BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
        );//this assigns the listener
    }
    //functions to handle back button events
    componentDidMount()
    {
        this._blurGoingSubscribe = this.props.navigation.addListener('willBlur', payload =>
                BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
            );
    }

    onBackButtonPressAndroid = () => {
        this.props.navigation.goBack();
        return true;
    };

    componentWillUnmount()
    {
        this._focusDoneSubscribe && this._focusDoneSubscribe.remove();
        this._blurGoingSubscribe && this._blurGoingSubscribe.remove();
    }
    //actual render
    render(){
        const { navigate } = this.props.navigation;
        return (
            <View style={{alignItems: 'center'}}>
                <View style={{height: 100,justifyContent: 'center',alignItems: 'center'}}>
                    <Text style={{fontSize: 20}}>Navigation BackHandler Tutorial</Text>
                    <Text style={{fontSize: 20}}>SCREEN ONE</Text>
                </View>
            </View>
        );
    }
}
0
Fadzly Othman