React Native:双击后退到应用程序

Mah*_*our 6 double-click exit react-native react-native-android react-native-ios

如何在不需要Redux的情况下两次单击后退按钮退出应用程序

我一直在寻找一种限制用户的解决方案,只需点击一下本机就可以退出应用程序.

Mah*_*our 13

import React, {Component} from 'react';
import {BackHandler, View, Dimensions, Animated, TouchableOpacity, Text} from 'react-native';

let {width, height} = Dimensions.get('window');


export default class App extends Component<Props> {

    state = {
        backClickCount: 0
    };

    constructor(props) {
        super(props);

        this.springValue = new Animated.Value(100);

    }

    componentWillMount() {
        BackHandler.addEventListener('hardwareBackPress', this.handleBackButton.bind(this));
    }

    componentWillUnmount() {
        BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton.bind(this));
    }

    _spring() {
        this.setState({backClickCount: 1}, () => {
            Animated.sequence([
                Animated.spring(
                    this.springValue,
                    {
                        toValue: -.15 * height,
                        friction: 5,
                        duration: 300,
                        useNativeDriver: true,
                    }
                ),
                Animated.timing(
                    this.springValue,
                    {
                        toValue: 100,
                        duration: 300,
                        useNativeDriver: true,
                    }
                ),

            ]).start(() => {
                this.setState({backClickCount: 0});
            });
        });

    }


    handleBackButton = () => {
        this.state.backClickCount == 1 ? BackHandler.exitApp() : this._spring();

        return true;
    };


    render() {

        return (
            <View style={styles.container}>
                <Text>
                    container box
                </Text>

                <Animated.View style={[styles.animatedView, {transform: [{translateY: this.springValue}]}]}>
                    <Text style={styles.exitTitleText}>press back again to exit the app</Text>

                    <TouchableOpacity
                        activeOpacity={0.9}
                        onPress={() => BackHandler.exitApp()}
                    >
                        <Text style={styles.exitText}>Exit</Text>
                    </TouchableOpacity>

                </Animated.View>
            </View>
        );
    }
}


const styles = {
    container: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center"
    },
    animatedView: {
        width,
        backgroundColor: "#0a5386",
        elevation: 2,
        position: "absolute",
        bottom: 0,
        padding: 10,
        justifyContent: "center",
        alignItems: "center",
        flexDirection: "row",
    },
    exitTitleText: {
        textAlign: "center",
        color: "#ffffff",
        marginRight: 10,
    },
    exitText: {
        color: "#e5933a",
        paddingHorizontal: 10,
        paddingVertical: 3
    }
};
Run Code Online (Sandbox Code Playgroud)

在snack.expo中运行:https://snack.expo.io/HyhD657d7


sut*_*her 11

我已经通过这种方式解决了它作为分离的功能组件。这样你就不需要为每个应用程序重新编码,只需要在你的新应用程序中包含这个组件就完成了!

import * as React from 'react';
import {useEffect, useState} from 'react';
import {Platform, BackHandler, ToastAndroid} from 'react-native';

export const ExecuteOnlyOnAndroid = (props) => {
  const {message} = props;
  const [exitApp, setExitApp] = useState(0);
  const backAction = () => {
    setTimeout(() => {
      setExitApp(0);
    }, 2000); // 2 seconds to tap second-time

    if (exitApp === 0) {
      setExitApp(exitApp + 1);

      ToastAndroid.show(message, ToastAndroid.SHORT);
    } else if (exitApp === 1) {
      BackHandler.exitApp();
    }
    return true;
  };
  useEffect(() => {
    const backHandler = BackHandler.addEventListener(
      'hardwareBackPress',
      backAction,
    );
    return () => backHandler.remove();
  });
  return <></>;
};

export default function DoubleTapToClose(props) {
  const {message = 'tap back again to exit the App'} = props;
  return Platform.OS !== 'ios' ? (
    <ExecuteOnlyOnAndroid message={message} />
  ) : (
    <></>
  );
}

Run Code Online (Sandbox Code Playgroud)

=>你唯一需要做的就是在你的 App 中包含这个组件。<=

因为 IOS 没有后退按钮,所以 IOS 不需要这个功能。上述组件会自动检测设备是否为 Android。

默认情况下,Toast 中显示的消息是用英语预定义的,但如果您添加一个名为messageDoubleTapToClose-Component的属性,您可以设置自己的消息。

...
import DoubleTapToClose from '../lib/android_doubleTapToClose'; 
...
return(
    <>
        <DoubleTapToClose />
        ...other Stuff goes here
    </>

Run Code Online (Sandbox Code Playgroud)

根据您的导航结构,您必须检查您是否在应用程序的初始屏幕上。就我而言,我有一个抽屉,里面有多个 StackNavigatiors。所以我检查当前屏幕是否是初始屏幕(索引:0),或者不是。如果是,我设置了一个 Hook-Variable,它只用于那些初始屏幕。

看起来像这样:

const isCurrentScreenInitialOne = (state) => {
  const route = state.routes[state.index];
  if (route.state) {
    // Dive into nested navigators
    return isCurrentScreenInitialOne(route.state);
  }
  return state.index === 0;
};

...
...

export default function App() {
...
  const [isInitialScreen, setIsInitialScreen] = useState(true);

  {isInitialScreen && (<DoubleTapToClose message="Tap again to exit app" />)}

...
...
<NavigationContainer
          ...
          onStateChange={(state) => {
            setIsInitialScreen(isCurrentScreenInitialOne(state));
          }}>

Run Code Online (Sandbox Code Playgroud)

如果该描述对您有所帮助,请不要错过投票

  • 多么聪明的方法@suther! (3认同)

Ant*_*noi 8

最简单的方法(直接粘贴到你的功能组件中):

const navigation = useNavigation();
const navIndex = useNavigationState(s => s.index);
const [backPressCount, setBackPressCount] = useState(0);

const handleBackPress = useCallback(() => {
  if (backPressCount === 0) {
    setBackPressCount(prevCount => prevCount + 1);
    setTimeout(() => setBackPressCount(0), 2000);
    ToastAndroid.show('Press one more time to exit', ToastAndroid.SHORT);
  } else if (backPressCount === 1) {
    BackHandler.exitApp();
  }
  return true;
}, [backPressCount]);

useEffect(() => {
  if (Platform.OS === 'android' && navIndex === 0) {
    const backListener = BackHandler.addEventListener(
      'hardwareBackPress',
      handleBackPress,
    );
    return backListener.remove;
  }
}, [handleBackPress]);
Run Code Online (Sandbox Code Playgroud)

您还可以将其包装在自定义挂钩中并在组件中使用该挂钩。


Ayu*_*sch 6

抱歉,如果我参加聚会迟到了,但我有类似的要求,并通过创建自己的自定义挂钩解决了它!

let currentCount = 0;
export const useDoubleBackPressExit = (exitHandler: () => void) => {
  if (Platform.OS === "ios") return;
  const subscription = BackHandler.addEventListener("hardwareBackPress", () => {
    if (currentCount === 1) {
      exitHandler();
      subscription.remove();
      return true;
    }
    backPressHandler();
    return true;
  });
};
const backPressHandler = () => {
  if (currentCount < 1) {
    currentCount += 1;
    WToast.show({
      data: "Press again to close!",
      duration: WToast.duration.SHORT,
    });
  }
  setTimeout(() => {
    currentCount = 0;
  }, 2000);
};
Run Code Online (Sandbox Code Playgroud)

现在我可以在任何我想要的地方使用它,只需执行以下操作:

useDoubleBackPressExit(() => { 
   // user has pressed "back" twice. Do whatever you want! 
});
Run Code Online (Sandbox Code Playgroud)