【问题标题】:How to handle exit app in one screen not in the whole app - React Native?如何在一个屏幕而不是整个应用程序中处理退出应用程序 - React Native?
【发布时间】:2019-03-22 19:36:39
【问题描述】:

我对 BackHandler 有一些问题,问题是

当运行应用程序并转到比方说注册屏幕并在我的手机中触摸背面时,它们将运行该功能并显示警报以确认,但现在当我转到任何其他屏幕并触摸背面时,它们会我需要在每个 backHandler.exitApp(); 上返回上一个屏幕。运行,虽然我写如果 routname 是 SignUp 只是退出应用程序而不是其他屏幕

这是我的代码

注册

    import React from "react";
    import {
      Text,
      TextInput,
      ActivityIndicator,
      View,
      KeyboardAvoidingView,
      ScrollView,
      Image,
      TouchableOpacity,
      BackHandler,
      Alert
    } from "react-native";
    export default class signUp extends React.Component {
      constructor(props) {
        super(props);

      }

      componentDidMount() {
        BackHandler.addEventListener("hardwareBackPress", this.backPressed);
      }

      componentWillUnmount() {
        BackHandler.removeEventListener("hardwareBackPress", this.backPressed);
      }
      backPressed = () => {
    let { routeName } = this.props.navigation.state;
    console.log("route is :  " + routeName);

    if (routeName == "SignUp") {
      console.log("ROUTE :  " + routeName);
      Alert.alert(
        "Exit App",
        "Do you want to exit?",
        [
          {
            text: "No",
            onPress: () => console.log("Cancel Pressed"),
            style: "cancel"
          },
          { text: "Yes", onPress: () => BackHandler.exitApp() }
        ],
        { cancelable: false }
      );
      return true;
    } else {
      return false;
    }
  };

      render() {....}
    }

路线

import { createStackNavigator, createAppContainer } from "react-navigation";
import React from "react";
import { View } from "react-native";
import Splash from "../screens/Splash";
import Home from "../screens/Home";
import SignUp from "../screens/SignUp";
import SignIn from "../screens/SignIn";
import ForgetPassword from "../screens/ForgetPassword";

const Routes = createStackNavigator(
  {
    Splash: {
      screen: Splash,
      navigationOptions: {
        header: null
      }
    },
    SignUp: {
      screen: SignUp,
      navigationOptions: () => ({
        // header: null
        title: "Sign Up",
        headerLeft: null,
        headerTintColor: "#fc0301",
        headerStyle: {
          borderBottomColor: "white"
        },
        headerTitleStyle: {
          color: "#fc0301",
          textAlign: "center",
          flex: 1,
          elevation: 0,
          fontSize: 25,
          justifyContent: "center"
        }
      })
    },
    SignIn: {
      screen: SignIn,
      navigationOptions: {
        title: "Sign In",
        headerRight: <View />,
        headerTintColor: "#fc0301",
        headerStyle: {
          borderBottomColor: "white"
        },
        headerTitleStyle: {
          color: "#fc0301",
          textAlign: "center",
          flex: 1,
          elevation: 0,
          fontSize: 25,
          justifyContent: "center"
        }
      }
    },
    ForgetPassword: {
      screen: ForgetPassword,
      navigationOptions: {
        header: null
      }
    },
    Home: {
      screen: Home,
      navigationOptions: {
        header: null
      }
    }
  },
  {
    initialRouteName: "Splash"
  }
);

export default createAppContainer(Routes);

【问题讨论】:

  • 默认的 BackButton 功能是:向堆栈顶部移动一步,如果您已经在顶部,它将退出应用程序,return true; 以防止默认行为,按你的后退按钮不会有任何作用。
  • @HendEl-Sahli 嗯,简单的问题是当我在注册屏幕并单击硬件返回按钮时,它会将我移动到启动屏幕并且它是异常的!所以我的想法是我只需要在注册屏幕和一些我想要的屏幕我想禁用硬件后退按钮,而不是在我在这里谈论“BackHandler Android”的每个屏幕中
  • 您的问题可以通过使用SwitchNavigator 来解决,它会呈现: 1. 启动画面。 2. 你的 StackNavigator 一旦你被引导到你的堆栈,backButton 将永远不会带你回到你的启动屏幕
  • @HendEl-Sahli 很抱歉这个评论,但我被卡住了,你有什么例子来实现一对一聊天“私人”而不是 Room 使用 firebase 作为后端!?

标签: javascript android reactjs react-native react-navigation


【解决方案1】:

您可以在调用警报之前检查屏幕是否已聚焦,而不是从导航中检查routeName。

更新后的代码可能如下所示。

if (this.props.navigation.isFocused()) {
    Alert.alert(
    "Exit App",
    "Do you want to exit?",
    [
      {
        text: "No",
        onPress: () => console.log("Cancel Pressed"),
        style: "cancel"
      },
      { text: "Yes", onPress: () => BackHandler.exitApp() }
    ],
    { cancelable: false }
    );
}

【讨论】:

  • 是的,这很有效,如果我需要在多个屏幕中运行警报,我需要在每个屏幕中调用此函数吗?例如,我想在 SignUp 和“Home”等中运行警报!
  • 如果您有特定的屏幕需要此功能,您可以在公共服务类中使用它并在 componentDidMount 上调用它。以便于维护。
  • 如何在 react-navigation V5 中处理它
  • 似乎在 v5 中不再是这种情况,navigation.isFocused() 总是返回 true,更糟糕的是 navigation.canGoBack() 总是返回 false,我不知道如何知道我什么时候在最上面堆栈,真的不能再回去了
  • 您是否尝试过使用 counter redux 操作,我们在找到此解决方案之前使用了 global counter。它将永远有效!
【解决方案2】:

版本 5+,尝试使用navigation.canGoBack()。

我是从Zennichimaro's comment 发现的。

如果您的堆栈中只有一个屏幕。

navigation.canGoBack() //=> false

如果堆栈中您下方至少有一个屏幕。

即如果有一个屏幕可以“返回”到。

navigation.canGoBack() //=> false

navigation.navigate( "screen2" );

navigation.canGoBack() //=> true

navigation.goBack();

navigation.canGoBack() //=> false

【讨论】:

    【解决方案3】:

    您必须通过递归调用 dangerouslyGetParent 来获取 ROOT 导航器的 navigation 对象

    例如 如果你有这样的层次结构:

    • 底部标签(TabNavigator)

      • 浏览器(StackNavigator)
      • 设置(堆栈导航器)
        • 关于(屏幕)

    并且您想在您的androidBackHandler 中获取当前的routeName 它连接在您的Browser 屏幕中,那么您应该通过调用dangerouslyGetParent 两次(这是您的导航树的深度)来获取您的BottomTabs 的导航对象:

    const bottomTabsNavigation = navigation
          .dangerouslyGetParent()
          .dangerouslyGetParent();
    

    如果您在About 屏幕上尝试console.log 您的bottomTabsNavigation,您应该会看到类似的内容

    【讨论】:

    • 很遗憾没用:/在每个屏幕上我都会显示警报
    • 我写你的代码只是在登录屏幕中添加 case "SignIn" alert"something" 来测试它们
    • 我做了一些魔法,我不知道它为什么会起作用:D 我只是将 routeName 替换为 this.props.navigation.isFocused(),它终于起作用了!!
    猜你喜欢
    • 1970-01-01
    • 2021-05-26
    • 1970-01-01
    • 2020-09-12
    • 2012-04-24
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    相关资源
    最近更新 更多