Mobile 개발/RN(React Native)

RN - swipe back, gesture back, edge back, back key control

히핑소 2020. 12. 25. 10:01
반응형

리액트 네비게이션 (stack) 사용 중에 IOS 의 경우

좌측 스와이프해서 back stack 으로 이동이 가능합니다.

 

map view 등을 사용할 경우에는 이 동작을 막지 않으면, 

지도 이동중에 back key 처럼 동작되어 불편함이 발생하므로

이부분 해결하고 넘어가야겠습니다.

 

- Swipe Back Disable

해결 방법은 gestureEnabled 한줄이면 됩니다.

단, 주로 안드로이드에서 쓰이는 gesture back 이나 back key를 제어하진 않습니다

gestureEnabled: false,

아래 doc 설명 처럼, Defaults to true on iOS, false on Android 입니다.

reactnavigation.org/docs/stack-navigator/#gestureenabled

 

createStackNavigator | React Navigation

Provides a way for your app to transition between screens where each new screen is placed on top of a stack.

reactnavigation.org

아래 코드에서 BottomTabScreen (MapView가 있는) 에만 적용.

const Stack = createStackNavigator();

export default class MainScreen extends Component {
  state = {
    finishIntro: false,
  }
  async componentDidMount() {
    setTimeout(() => {
      SplashScreen.hide();
    }, 1000);
    try {
      AsyncStorage.getItem("finishIntro").then((value) => {
        if (value === "true") {
          this.setState({finishIntro: true});
        }
      });
    } catch (err) {
      console.log("udonPeople error: " + err)
    }
  }
  onRenderItem = ({ item }) => {
    return (
      <View style={globalStyles.IntroSlideContainer}>
        <Image style={globalStyles.IntroSlideImageContainer} source={item.image} />
      </View>
    );
  }
  onDone = () => {
    this.setState({finishIntro:true});
    setAsyncStorage("finishIntro", "true");
  }

  render() {
    if (this.state.finishIntro) {
      return (
        <NavigationContainer>
            <Stack.Navigator>
                <Stack.Screen name="Auth" component={AuthScreen} 
                options={() => ({
                  headerShown:false,
                  headerTitle:"로그인",
                })}
                />
                <Stack.Screen name="Home" component={BottomTabScreen}
                options={() => ({
                  // headerLeft:() => <Header left={true} navigation={navigation}/>,
                  // headerRight:() => <Header left={false} navigation={navigation}/>,
                  // headerLeft:null,
                  // headerTitleAlign:"center",
                  headerShown:false,
                  headerTitle:"지도보기",
                  gestureEnabled: false,
                })}
                />
                <Stack.Screen name="LocationSetting" component={RegionScreen}
                options={() => ({
                  headerTitleAlign:"center",
                  headerTitle:"지역 설정",
                })}
                />
                <Stack.Screen name="Setting" component={SettingScreen}
                options={() => ({
                  headerTitleAlign:"center",
                  headerTitle:"설정",
                })}
                />
                <Stack.Screen name="WebCafe" component={WebCafeScreen}
                options={() => ({
                  headerTitleAlign:"center",
                  headerTitle:"카페 방문",
                })}
                />
                <Stack.Screen name="AppManual" component={ManualScreen}
                options={() => ({
                  headerTitleAlign:"center",
                  headerTitle:"공지사항",
                })}
                />
            </Stack.Navigator>
        </NavigationContainer>
      );
    } else {
      return <AppIntroSlider renderItem={this.onRenderItem} data={introSlide} onDone={this.onDone}/>;
    }
  }
}

 

왼쪽 -  수정 후 mapview 에서 더이상 swipe back 불가(settingscreen은 가능)

오른쪽- 적용 전(mapview swipe back 가능)

 

- gesture back, edge back, back key disable

android back key event 를 control 하는 코드는 다음과 같습니다.

그리고, back key 2회시 (3초안에) app 종료하는 코드도 함께 추가 했습니다.

onBackPressed 에서 return true 시 back 을 block 시켜버립니다.

import {BackHandler, ToastAndroid } from "react-native";
state = {
  validCloseWindow: false,
};

componentDidMount() {
  if (Platform.OS === 'android') {
  	BackHandler.addEventListener('hardwareBackPress', this.onBackPressed);
  }
}
  
  onBackPressed = () => {
    const duration = 3 * 1000;
    if (this.state.validCloseWindow) {
      BackHandler.exitApp();
    }
    this.setState({validCloseWindow: true});
    setTimeout(() => {
      this.setState({validCloseWindow: false});
    }, duration);
    ToastAndroid.show("버튼을 한번 더 누르면 종료됩니다", duration);
    return true;
  }
  componentWillUnmount() {
    if (Platform.OS === 'android') {
      BackHandler.removeEventListener('hardwareBackPress', this.onBackPressed);
    }
  }

 

그리고, Preventing going back 코드는

swipe back 뿐만 아니라, back 관련된 걸 다 막아버립니다.

class component 는 componentDidMount() 에, function component 는 useEffect() 에 밀어넣으면 됩니다.

 

실제 써보니, 잘 되던 다른 동작까지 막아 버려서

좀더 파보고 써야겠습니다.

A stack 에 아래 코드를 넣으면,

A -> B -> C-> A stack navigate 이동 시 A로 못돌아오네요.

  componentDidMount() {
    this.props.navigation.addListener('beforeRemove', (e) => {
      e.preventDefault();
      console.log(" beforeRemove " + e);
    });
  }

reactnavigation.org/docs/preventing-going-back

 

Preventing going back | React Navigation

Available in version 5.7+

reactnavigation.org

반응형