Programing

기본 반응:종료 앱으로 다시 더블 백 누르기

c10106 2022. 3. 16. 21:51
반응형

기본 반응:종료 앱으로 다시 더블 백 누르기

Redex 없이 뒤로 버튼을 두 번 클릭하여 응용 프로그램을 종료하는 방법

원클릭으로 리액션 네이티브로 사용자를 제한하고 애플리케이션에서 벗어나지 않는 솔루션을 찾고 있었다.

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
    }
};

스낵으로 달리십시오. https://snack.expo.io/HyhD657d7

분리 기능 컴포넌트로서 이렇게 해결했다.이렇게 하면 각 앱에 대해 리코딩할 필요가 없으며, 새 앱에 구성 요소만 포함하면 완료!

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} />
  ) : (
    <></>
  );
}

=> 에 이 구성 요소를 포함하기만 하면 된다.<=

IOS는 백버튼이 없기 때문에 IOS는 이 기능이 필요하지 않다.위의 컴포넌트는 자동으로 장치가 안드로이드인지 아닌지를 감지한다.

기본적으로 토스트에 표시된 메시지는 영어로 미리 정의되어 있지만 이름이 지정된 속성을 추가하면 직접 메시지를 설정할 수 있다.messageDoubleTapToClose-Component로 이동하십시오.

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

Nav-Structure에 따라 앱의 초기 화면에 있는지 확인해야 한다.내 경우에는 서랍 안에 여러 개의 스택내비게이터가 있어.그래서 나는 현재 화면이 초기 화면인지(index:0) 아닌지 확인한다.만약 그렇다면, 나는 초기 Screens에만 사용될 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));
          }}>

만약 그 묘사가 도움이 된다면, 투표하는 것을 놓치지 마라.

백핸들러와 토스트안드로이드를 사용하는 것이 더 나은 접근 방법일 것이다.

import { BackHandler, ToastAndroid } from 'react-native';
//rest of imports

class SomeClass extends Component{
    constructor(state, props) {
        super(state, props)
        this.state = {
            validCloseWindow: false
        }
    }
    async componentDidMount() {
        BackHandler.addEventListener('hardwareBackPress', this.handleBackButton.bind(this));
    }

    componentWillUnmount() {
        BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton.bind(this));
    }
    handleBackButton = () => {
        if (!this.props.navigation.canGoBack()) {
            if (this.state.validCloseWindow)
                return false;
            this.state.validCloseWindow = true
            setTimeout(() => {
                this.state.validCloseWindow = false
            }, 3000);
            ToastAndroid.show("Press Again To Exit !", ToastAndroid.SHORT);
            return true;
        }
    };
//rest of component code
}

초기 경로 페이지에서 내비게이션에 사용하십시오.

파티에 늦었다면 미안한데 비슷한 요구사항이 있어서 나만의 맞춤 훅을 만들어서 해결했어!

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);
};

이제 다음 작업을 수행하기만 하면 원하는 곳 어디에서나 사용할 수 있다.

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

아래 코드 설명 자체.요령은 모든 페이지에 있는 것이 아니라 메인 AppContainer에 있는 것이다.

import {  Alert,  BackHandler,  ToastAndroid } from 'react-native';
import {  StackActions } from 'react-navigation';
// common statless class variable.
let backHandlerClickCount = 0;

class App extends React.Component {
    constructor(props) {
      super(props);
      // add listener to didFocus
      this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
        BackHandler.addEventListener('hardwareBackPress', () => this.onBackButtonPressAndroid(payload)));
    }

    // remove listener on unmount 
    componentWillUnmount() {
      if (this._didFocusSubscription) {
        this._didFocusSubscription.remove();
      }
    }

    onBackButtonPressAndroid = () => {
      const shortToast = message => {
        ToastAndroid.showWithGravityAndOffset(
          message,
          ToastAndroid.SHORT,
          ToastAndroid.BOTTOM,
          25,
          50
        );

        const {
          clickedPosition
        } = this.state;
        backHandlerClickCount += 1;
        if ((clickedPosition !== 1)) {
          if ((backHandlerClickCount < 2)) {
            shortToast('Press again to quit the application!');
          } else {
            BackHandler.exitApp();
          }
        }

        // timeout for fade and exit
        setTimeout(() => {
          backHandlerClickCount = 0;
        }, 2000);

        if (((clickedPosition === 1) &&
            (this.props.navigation.isFocused()))) {
          Alert.alert(
            'Exit Application',
            'Do you want to quit application?', [{
              text: 'Cancel',
              onPress: () => console.log('Cancel Pressed'),
              style: 'cancel'
            }, {
              text: 'OK',
              onPress: () => BackHandler.exitApp()
            }], {
              cancelable: false
            }
          );
        } else {
          this.props.navigation.dispatch(StackActions.pop({
            n: 1
          }));
        }
        return true;
      }

    }
import React, { Component } from 'react'
import { Text, View, StyleSheet, TouchableOpacity,BackHandler} from 'react-native'
import { Toast } from "native-base";

class Dashboard extends Component {

    state={
        clickcount:0
    }


    componentDidMount(){
        BackHandler.addEventListener("hardwareBackPress",()=>{
            this.setState({'clickcount':this.state.clickcount+1})
            this.check();
            return true
        })
    }

    check=()=>{
        if(this.state.clickcount<2){
            Toast.show({
                text:`Press back again to exit App `,
                duration:2000,
                onClose:()=>{this.setState({'clickcount':0})}
            })

        }
        else if(this.state.clickcount==2)
        {
            BackHandler.exitApp()
        }
    }

    render() {
        return (

                <View style={styles.container}>
                    <Text> Hello this is the Dashboard Screen</Text>
                </View>

        )
    }
}

export default Dashboard

const styles = StyleSheet.create({
 container:{
     flex:1,
     marginTop:25,
     justifyContent:'center',
     alignItems:'center',
     borderBottomLeftRadius:30,
     borderBottomRightRadius:30,
     backgroundColor:'#fff'
    },
  });

현재 가장 단순한 접근 방식:

App.js:

componentDidMount() {
    const backHandler=BackHandler.addEventListener('hardwareBackPress', ()=>{
        if(this.backHandler){
            return false;
        }
        Toast.show('再按一次退出应用');
        this.backHandler=backHandler;
        setTimeout(()=>{
            this.backHandler=null;
        },2000);
        return true;
    });
}

componentWillUnmount() {
    this.backHandler.remove();
}

내가 앱에서 사용한 가장 간단한 해결책은 이것이다.그것은 반응 항법 4.4.1과 함께 잘 작동하며 여기에 제공된 다른 정답보다 훨씬 짧다.

import React from 'react';
import { BackHandler, ToastAndroid} from 'react-native';

export default class LoginScreen extends React.Component {

    state = {
        canBeClosed: false
    }

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

    handleBackButton = () => {
        if (this.props.navigation.isFocused()) {
            if (this.state.canBeClosed)
                return this.state.canBeClosed = false;
    
            else {
                setTimeout(() => { this.state.canBeClosed = false }, 3000);    
                ToastAndroid.show("Press Again To Exit !", ToastAndroid.SHORT);
    
                return this.state.canBeClosed = true
            }   
        }
    };

 //some code

}

가장 간단한 것

import { useNavigationState } from '@react-navigation/native';
import { BackHandler, Alert } from 'react-native';
//index to get index of home screen when index == 0 in navigation stack
const index = useNavigationState(state => state.index);

const backAction = () => {
    Alert.alert("Hold on!", "Are you sure you want to Exit App?", [
        {
            text: "Cancel",
            onPress: () => null,
            style: "cancel"
        },
        { text: "YES", onPress: () => BackHandler.exitApp() }
    ]);
    return true;
};

useEffect(() => {
    // if index==0 this is initial screen 'Home Screen'
    if (index == 0) {
        BackHandler.addEventListener("hardwareBackPress", backAction);
        return () =>
            BackHandler.removeEventListener("hardwareBackPress", backAction);
    }
}, [index]);

참조URL: https://stackoverflow.com/questions/52253072/react-native-double-back-press-to-exit-app

반응형