React Native에서 화면 회전시 레이아웃 붕괴에 대응하면 KeyboardAvoidingView가 작동하지 않게 되었다

이하의 2개 세워입니다.
  • React Native로 화면 회전하면 Android의 경우 레이아웃이 무너져 버렸기 때문에 대응했다
  • 이번에는 KeyboardAvoidingView가 더 이상 작동하지 않으므로 대체 방법으로 피했습니다

  • 환경
  • React Native 0.61.5
  • iOS 13.5.1
  • Android 10

  • React Native에서 화면 회전하면 레이아웃 붕괴가 발생했습니다.



    KeyboardAvoidingView를 root에 배치한 화면을 Portrait=>Landscape=>Portrait로 회전시키면 수수께끼의 공간이 발생. 안드로이드에서 Flex가 제대로 움직이지 않는 거동을 했습니다.



    소스는 이런 느낌입니다.

    대응 전
    class Hoge extends React.Component {
      render() {
        return (
          <KeyboardAvoidingView
            style={{
              flex: 1
            }}
            behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
          >
            // ...
          </KeyboardAvoidingView>
        );
      }
    );
    

    여러가지 해결 방법을 찾아 수당대로 시험해 보았는데, StackOverflow에서 찾은 방법 에서, state를 개입시켜 재render 시키도록(듯이) 하는 것으로 올바르게 레이아웃 되게 되었습니다.

    대응 후
    class Hoge extends React.Component {
      _onLayout = () => {
        this.setState({ width: Dimensions.get('window').width }); 
      }
    
      render() {
        return (
          <KeyboardAvoidingView
            onLayout={this._onLayout}
            style={{
              flex: 1,
              width
            }}
            behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
          >
            // ...
          </KeyboardAvoidingView>
        );
      }
    );
    

    이것으로 일건 낙착··라고 생각했는데,,

    이번에는 KeyboardAvoidingView가 더 이상 작동하지 않습니다.



    상기의 대응을 실시하는 것으로, iOS·Android 모두, KeyboardAvoidingView가 키보드를 피하지 않는 단순한 View로 되어 버렸습니다.

    View의 중첩 관계를 바꾸거나, 여러가지 시험해 보았지만 잘 안된다. 결국 KeyboardAvoidingView를 포기하고 대신 KeyboardSpacer이라는 라이브러리를 사용하면 잘 작동했습니다.

    대응 후 (개)
    class Hoge extends React.Component {
      _onLayout = ({nativeEvent}) => {
        const width = Dimensions.get('window').width;
        const height = Dimensions.get('window').height;
        const screenOffset = height - nativeEvent.layout.height;
        this.setState({ width, screenOffset });
      };
    
      render() {
        return (
          <View
            onLayout={this._onLayout}
            style={{
              flex: 1,
              width
            }}
            behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
          >
            // ...
            <KeyboardSpacer topSpacing={(-1) * this.state.screenOffset} />
          </View>
        );
      }
    );
    

    처음에는 Android에서 생각하는 것처럼 작동하지 않았지만 AndroidManifest에 windowSoftInputMode="adjustResize"를 지정하면 잘 작동합니다.

    또한 ReactNavigation의 BottomTabNavigator를 사용하기 때문에 Window와 View 사이의 차이를 계산하고 KeyboardSpacertopSpacing로 설정했습니다.

    결론



    화면 회전 연결로 iPhone에서 Landscape로 했을 때 상태 표시줄이 사라지는 영향으로 레이아웃이 무너지는 문제도 발생하고 있었기 때문에 상태 표시줄의 높이를 store로 관리하도록 하기도 했습니다.
    이런 작은 세공이 여러가지 필요한 것이 까다로운 곳입니다.

    이제 온천에도 가고 싶네요.

    좋은 웹페이지 즐겨찾기