简体   繁体   中英

How to stop the Android Hardware Back Button from functioning in react-navigation for react-native?

I am developing a trivia game, I am using react-navigation to handle navigation, I have 3 components, (newGame, Questions, Results ) I don't want the user to go back to the questions from the results page if the no. of questions has been exhausted, however, pressing the back button ( Android Hardware ) is taking him back to the questions. I then tried to handle the hardware back button like so:

componentWillMount() {
      this.props.gameState(true);
      BackHandler.addEventListener('hardwareBackPress', () => {
        if (this.props.gamePlaying) { // Currently set to true. I will set it to false again on NewGame Page.
          this.props.navigation.navigate('NewGame');
        }
      });
    }

However, this is taking the user to the NewGame screen but immediately, it is bouncing back to the results page as it is firing the NAVIGATION/BACK as well immediately in the NewGame page. Which is again taking it back to the results page.

Possible fix?

I want to stop the the back button to fire after I have landed in the NewGame component page. Is there a way to do it?

My Environment

react-navigation = ^1.0.0-beta.11 react-native = 0.44.0

You need to return true to indicate you have handled the back button yourself as you can see in the docs .

if one subscription returns true then subscriptions registered earlier will not be called

Your code should look like this:

componentWillMount() {
    this.props.gameState(true);
    BackHandler.addEventListener('hardwareBackPress', () => {
        if (this.props.gamePlaying) {
            this.props.navigation.navigate('NewGame');
            return true; // This will prevent the regular handling of the back button
        }

        return false;
    });
}

One way to stop the button from functioning is to introduce logic into your BackHandler eventlistener when you start it, like this:

BackHandler.addEventListener('hardwareBackPress', () => {
    const { dispatch, nav } = this.props
    if (nav.routes.length === 1 && (nav.routes[0].routeName === 'Login' || nav.routes[0].routeName === 'Start')) return false
    dispatch({ type: 'Navigation/BACK' })
    return true
})

Notice how we are observing conditions. The key to this question is to return true or false from the event listener. false stops the Hardware Back Button from functioning. true clean-exits from the event.

Here is another example to illustrate:

BackHandler.addEventListener('hardwareBackPress', () => {
    const { dispatch, nav } = this.props
    if (nav.routes[0].routeName === 'TriviaQuestion') return false
    if (!playTimeLeft && (nav.routes[0].routeName === 'TriviaQuestion')) return false
    if (nav.routes[0].routeName === 'InvasiveDialog') return false
    dispatch({ type: 'Navigation/BACK' })
    return true
})

Here is some sample code that is useful to look at for more purposes than just stopping the Back Button from functioning:

import React, { Component } from 'react'
import { Platform, BackHandler } from 'react-native'
import { Provider, connect } from 'react-redux'
import { addNavigationHelpers } from 'react-navigation'
import { NavigationStack } from './navigation/nav_reducer'
import store from './store'

class App extends Component {
    componentWillMount() {
        if (Platform.OS !== 'android') return
        BackHandler.addEventListener('hardwareBackPress', () => {
            const { dispatch, nav } = this.props
            if (nav.routes.length === 1 && (nav.routes[0].routeName === 'Login' || nav.routes[0].routeName === 'Start')) return false
            dispatch({ type: 'Navigation/BACK' })
            return true
        })
    }

    componentWillUnmount() {
        if (Platform.OS === 'android') BackHandler.removeEventListener('hardwareBackPress')
    }

    render() {
        const { dispatch, nav } = this.props
        const navigation = addNavigationHelpers({
            dispatch,
            state: nav
        })
        return <NavigationStack navigation={navigation} />
    }
}

const mapStateToProps = ({ nav }) => ({ nav })
const RootNavigationStack = connect(mapStateToProps)(App)

const Root = () => (
    <Provider store={store}>
        <RootNavigationStack />
    </Provider>
)

export default Root

If you find this post while trying to make your Back Button simply work, then just copy my last example as closely as possible. Use the event listener exactly as shown and test your app first to see how it works.

If you are using Redux, this is what you want.

NavigationStack simply refers to export const NavigationStack = StackNavigator({ ...etc }) in another file.

when user switch between screens in StackNavigator there is a back button by default, we can fix it by setting : headerLeft to null

static navigationOptions =({navigation}) => {
    return {
        title: 'Rechercher une ville',
        headerLeft: null,
    }  
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM