[React-Native] KeyboardAvoidingView와 ScrollView

강승묵·2024년 6월 5일
3

React-Native

목록 보기
4/4
post-thumbnail

ScrollView 안에서 multiline인 TextInput 사용시, 줄바꿈이 일어날 때 자동으로 스크롤 되지 않는 문제 해결

TextInputscrollEnabled={false} 속성을 추가하면 자동으로 스크롤이 된다. 하지만, 키보드가 있는 영역은 가려지게 되어 결국 안보이게 된다.

 <ScrollView>
   <TextInput  
     onChangeText={(text) => {
      setTitleText(text);
    }}
     multiline={true}
     scrollEnabled={false}
     />
 </ScrollView>

키보드가 TextInput의 문자를 가리는 문제 해결

1. ScrollView 대신에 KeyboardAvoidingView를 사용해 해결

npm install react-native-keyboard-aware-scroll-view을 하여 이 라이브러리를 설치한 뒤, ScrollView 대신에 KeyboardAwareScrollView을 사용한다. 그러면 문자가 가려지지 않는다.

 <KeyboardAwareScrollView style={{ flex: 1 }}>
   <TextInput  
     onChangeText={(text) => {
      setTitleText(text);
    }}
     multiline={true}
     scrollEnabled={false}
     />
 </KeyboardAwareScrollView>

2.KeyboardAvoidingView로 전체를 감싸고, attribute로 behavior="padding"을 넣어줘 해결

KeyboardAvoidingView에 속성으로 behavior="padding"을 추가하면, 키보드에 의해 문자가 가려지지 않는다. 속성을 추가하지 않으면 문자가 가려지니 주의!

<KeyboardAvoidingView  behavior="padding" style={{ flex: 1 }}>
 <ScrollView>
   <TextInput  
     onChangeText={(text) => {
      setTitleText(text);
    }}
     multiline={true}
     scrollEnabled={false}
     />
 </ScrollView>
<KeyboardAvoidingView>

키보드가 열리거나 닫힐 때, 스크린 하단에서 키보드를 따라다니는 '버튼 바(?)'를 만들기

위의 방법에서 나는 2번으로 진행했다. 2번으로 하면 그냥 ScrollView 아래에 버튼들을 추가하면 된다.KeyboardAvoidingViewbehavior="padding"을 추가하면, 키보드가 나올 때 KeyboardAvoidingView 내부에 있는 모든 컴포넌트들을 다 위로 올려주기 때문!

근데 주의할 점이KeyboardAvoidingView의 속성으로 keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}을 추가해줘야한다. IOS에서는 조금 더 Offset을 줘야 '버튼 바'가 가려지지 않는다. 하지만, Android에서 Offset을 주면 키보드를 열지 않았을 때, '버튼 바'만 붕 뜨는 일이 발생한다.

<KeyboardAvoidingView  
  behavior="padding" 
  keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}
  style={{ flex: 1 }}>
 <ScrollView>
   <TextInput  
     onChangeText={(text) => {
      setTitleText(text);
    }}
     multiline={true}
     scrollEnabled={false}
     />
 </ScrollView>
  
  <View style={styles.floatingButtonContainer}>
    <Button title="Button1" />
    <Button title="Button2" />
  </View>
<KeyboardAvoidingView>

IOS에서 ScrollView 글을 작성한 뒤 키보드 안 닫힘 문제 해결, ScrollView 내부 버튼 안눌림 문제 해결

첫 번째 문제는 ScrollViewkeyboardDismissMode="on-drag" 속성을 추가하면 해결할 수 있다. 이는 드레그를 해서 키보드를 내릴 수 있게 해준다.

두 번째 문제가 발생하는 이유는 ScrollView 내부에서 버튼을 누르려면 일단 키보드가 없어진 다음에 버튼이 눌려야했기 때문이며,이로 인해 동작이 부자연스러웠던 것이다. 따라서 키보드가 켜진 상태에서도 버튼을 누를 수 있게 해야한다.ScrollViewkeyboardShouldPersistTaps="always" 를 해주면, 키보드가 있는 상태에서도 버튼을 누를 수 있다.

<KeyboardAvoidingView  
  behavior="padding" 
  keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}
  style={{ flex: 1 }}>
 <ScrollView
   keyboardDismissMode="on-drag"
   keyboardShouldPersistTaps="always" 
  >
   <TextInput  
     onChangeText={(text) => {
      setTitleText(text);
    }}
     multiline={true}
     scrollEnabled={false}
     />
 </ScrollView>
  
  <View style={styles.floatingButtonContainer}>
    <Button title="Button1" />
    <Button title="Button2" />
  </View>
<KeyboardAvoidingView>

TextInput의 가장 끝에 문자를 입력하면 갑자기 맨 위로 자동 스크롤되는 문제 해결

가장 끝에서 확 올라가는 현상 해결

여러 테스트를 하던 중, 위 문제가 발생했다. TextInput을 입력할 때 항상 가장 끝, 그러니까 가장 우측 하단에 문자를 입력한 다음에 또 문자를 입력하면 갑자기 위로 스크롤 됐다. 우측 하단에 문자를 입력할 때만 이 문제가 나오는 것을 보고 TextInput의 크기와 연관이 있다고 생각했다. 뚜렷한 해결법을 찾지 못하다가 Handling TextInput in react native라는 제목을 블로그를 발견했고, 위 문제를 해결할 수 있었다.

결론은 TextInput의 크기가 변했을 시, 크기를 늘려주면 된다. 이를 위해 TextInput의 속성으로

	style={[styles.textBody, { height: bodyTextHeight }]}
	onContentSizeChange={
	//+100 정도 해줘야 TextInput 젤 위로 다시 올라가는 현상을 방지해줌
	(event) => setBodyTextHeight(event.nativeEvent.contentSize.height + 100)
    }

을 추가했다.
onContentSizeChange를 통해 TextInput의 크기 변화가 있을 때 높이를 받아오고, const [bodyTextHeight, setBodyTextHeight] = useState(0);를 설정하여 이 State로 높이를 받아오게 했다. 그리고 style에 변화된 높이를 반영해주어 높이 변화에 맞춰 높이 값을 변경해줬다. 또한 넉넉하게 100 정도 더 크게 해줬는데, 그냥 event.nativeEvent.contentSize.height로 높이를 설정해주면 제일 위로 올라가는 현상이 다시 나오기 때문에 Offset으로 100만큼 더 추가했다.

<KeyboardAvoidingView
  behavior="padding"
  keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}
  style={{ flex: 1 }}
  >
  <ScrollView
    enableResetScrollToCoords={false}
    keyboardDismissMode="on-drag"
    keyboardShouldPersistTaps="always"
    >
    <TextInput
      style={[styles.textBody, { height: bodyTextHeight }]}
      placeholder="Body"
      multiline={true}
      onChangeText={(text) => {
        setBodyText(text);
      }}
      onContentSizeChange={
        //+100 정도 해줘야 TextInput 젤 위로 다시 올라가는 현상을 방지해줌
        (event) =>
        setBodyTextHeight(event.nativeEvent.contentSize.height + 100)
      }
      scrollEnabled={false}
      />
  </ScrollView>

  <View style={styles.floatingButtonContainer}>
    <Button title="Button1" />
    <Button title="Button2" />
  </View>
</KeyboardAvoidingView>
profile
멋진 개발자 되기

1개의 댓글

comment-user-thumbnail
2025년 7월 7일

선생님의 글이 저를 살렸습니다.. 감사합니다 :)

답글 달기