로그인 폼을 만들다 보면 늘 같은 곳에서 막힌다. 화면 아래쪽 입력창을 탭하면 키보드가 올라오면서 그 입력창을 그대로 덮어버린다. 내가 지금 뭘 치고 있는지 안 보인다.
RN 기본 해법은 KeyboardAvoidingView인데, 이게 iOS에서는 behavior="padding", Android에서는 "height"를 줘야 그나마 비슷하게 동작한다. 플랫폼마다 분기를 태워야 하고, 그마저도 헤더 높이나 SafeArea가 끼면 계산이 어긋나서 입력창이 붕 뜨거나 여전히 가려진다. 매번 이걸 손으로 맞추는 게 지겨웠다.
react-native-keyboard-controller
react-native-keyboard-controller는 네이티브 레이어에서 키보드 높이와 애니메이션을 프레임 단위로 추적해서, iOS/Android 구분 없이 똑같이 부드럽게 밀어준다. Reanimated 기반이라 JS 스레드 끊김도 없다.
npm install react-native-keyboard-controller react-native-reanimated
Expo면 dev client가 필요하다. 최상단을 KeyboardProvider로 감싸는 것부터 시작한다.
import { KeyboardProvider } from 'react-native-keyboard-controller';
export default function App() {
return (
<KeyboardProvider>
<RootNavigator />
</KeyboardProvider>
);
}
KeyboardAvoidingView 갈아끼우기
가장 반가운 건 드롭인 교체가 된다는 점이다. import만 바꾸면 끝이고, behavior 플랫폼 분기가 필요 없다.
import { KeyboardAvoidingView } from 'react-native-keyboard-controller';
function LoginForm() {
return (
<KeyboardAvoidingView behavior="padding" style={{ flex: 1 }}>
<TextInput placeholder="이메일" />
<TextInput placeholder="비밀번호" secureTextEntry />
<Button title="로그인" onPress={submit} />
</KeyboardAvoidingView>
);
}
스크롤 폼이면 KeyboardAwareScrollView
입력창이 여러 개라서 스크롤이 필요한 화면이라면 이쪽이 더 낫다. 포커스된 입력창으로 자동 스크롤해주고, 키보드 높이만큼 아래 여백도 알아서 확보한다.
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';
<KeyboardAwareScrollView bottomOffset={20} style={{ flex: 1 }}>
<TextInput placeholder="이름" />
<TextInput placeholder="주소" />
<TextInput placeholder="메모" multiline />
</KeyboardAwareScrollView>
bottomOffset은 포커스된 입력창과 키보드 사이에 남길 간격이다. 20 정도면 입력창이 키보드에 딱 붙지 않고 살짝 떠서 보기 편하다.
정리
키보드 대응은 RN에서 은근히 시간 잡아먹는 작업인데, 이 라이브러리 하나로 플랫폼 분기와 높이 계산을 통째로 걷어낼 수 있었다. 단순 폼은 KeyboardAvoidingView, 스크롤이 있으면 KeyboardAwareScrollView — 이 두 개만 기억하면 대부분 해결된다. 새 프로젝트라면 처음부터 이걸 깔고 시작하는 걸 추천한다.