Expo

Expo KeyboardAvoidingView 사용법: 키보드가 화면을 가릴 때 해결하기

2026.03.10·수정 2026.05.12·약 14분

이 글에서 정리하는 내용

Expo에서 이 컴포넌트를 왜 쓰는지부터 시작해서, behavior 선택 기준, keyboardVerticalOffset의 감각, ScrollView와 함께 쓰는 흐름, Android에서 자주 겪는 탭 밀림 문제까지 한 번에 정리합니다.

KeyboardAvoidingView는 무엇을 해결하는가

Expo KeyboardAvoidingView 사용법: 키보드 가림 해결 핵심 개념을 설명하는 첫 번째 본문 이미지

Expo에서 입력 화면을 만들다 보면 화면은 멀쩡해 보이는데, 키보드가 올라오는 순간 마지막 입력창이나 하단 버튼이 가려지는 장면을 자주 만나게 됩니다. 처음에는 TextInput만 잘 배치하면 끝날 것처럼 보이지만, 모바일 화면은 키보드가 나타나는 순간 실제로 사용할 수 있는 세로 영역이 줄어들기 때문에 레이아웃 자체가 다시 반응해야 합니다.

이때 는 키보드 높이에 맞춰 자신의 높이, 위치, 또는 아래쪽 패딩을 조정해서 입력 UI가 계속 보이도록 도와줍니다. 결국 이 컴포넌트의 핵심은 보기 좋게 움직이는 데 있는 것이 아니라, 입력 흐름이 끊기지 않도록 만드는 데 있습니다. 그래서 로그인, 회원가입, 프로필 수정, 문의 작성처럼 입력이 중심인 화면이라면 가장 먼저 떠올려볼 수 있는 기본 도구입니다.

기본 개념 먼저 잡기

import { KeyboardAvoidingView, Platform, TextInput, View } from 'react-native'; export default function LoginScreen() { return ( <KeyboardAvoidingView // iOS에서는 padding이 가장 무난한 출발점인 경우가 많습니다. behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={{ flex: 1 }} > <View style={{ flex: 1, justifyContent: 'center', padding: 24 }}> <TextInput placeholder="이메일" /> <TextInput placeholder="비밀번호" secureTextEntry /> </View> </KeyboardAvoidingView> );
}

처음 적용할 때는 이 정도 형태로 시작하는 편이 가장 이해하기 쉽습니다. 핵심은 화면 전체를 감싸는 컨테이너에 flex: 1을 주고, 그 바깥쪽에서 가 레이아웃 변화를 맡도록 두는 것입니다. 입력창만 부분적으로 감싸면 기대한 만큼 밀리지 않는 경우가 많고, 부모 뷰의 높이 계산이 불안정하면 효과가 없는 것처럼 보일 수도 있습니다.

behavior 속성은 어떻게 이해하면 되는가

를 사용할 때 가장 많이 헷갈리는 값이 behavior입니다. 이름만 보면 단순 옵션처럼 보이지만, 실제로는 키보드가 올라왔을 때 레이아웃을 어떤 방식으로 바꿀지 정하는 핵심 값입니다. 같은 값을 넣어도 iOS와 Android에서 체감 결과가 다르게 보일 수 있기 때문에이 값을 외우는 방식보다 화면 구조와 플랫폼 차이를 함께 이해하는 편이 훨씬 실무적입니다.

height, position, padding 차이

<KeyboardAvoidingView behavior="height" style={{ flex: 1 }} />
// 컨테이너 높이를 줄여서 공간을 확보합니다. <KeyboardAvoidingView behavior="position" style={{ flex: 1 }} />
// 컨텐츠 위치를 이동시키는 방식입니다. <KeyboardAvoidingView behavior="padding" style={{ flex: 1 }} />
// 아래쪽 패딩을 늘려 키보드만큼 띄웁니다.

직접 써보면 padding은 가장 직관적으로 느껴지는 경우가 많고, position은 특정 영역을 통째로 위로 올리고 싶을 때 생각보다 잘 맞습니다. 반면 height는 전체 레이아웃이 다시 계산되기 때문에 구조에 따라 자연스러울 때도 있고, 갑자기 답답하게 줄어드는 느낌을 줄 때도 있습니다. 그래서 정답 하나를 외우기보다, 지금 화면이 “아래 패딩만 늘리면 충분한 구조인지”, “컨텐츠 묶음을 위로 올려야 하는 구조인지”를 먼저 보는 편이 정확합니다.

추가로 React Native 공식 문서를 보면 contentContainerStyle은 behavior가 position일 때 내용 컨테이너 스타일에 적용되고, enabled로 동작 자체를 켜거나 끌 수 있습니다. 평소에는 잘 쓰이지 않더라도, 특정 화면에서만 동작을 잠시 꺼야 하거나 position 기반 레이아웃을 더 세밀하게 다뤄야 할 때 알아두면 도움이 됩니다.

옵션 이럴 때 먼저 시도
padding iOS 중심의 일반 폼 화면가장 무난한 출발점
position 특정 입력 영역을 통째로 위로 올리고 싶은 화면

Expo 화면에서 실무적으로 적용하는 방법

실무에서는 이 컴포넌트 하나만 넣는다고 끝나지 않습니다. 헤더가 있고가 있고, 입력창이 길게 이어지고, 하단 버튼도 붙는 순간 offset과 스크롤 처리까지 같이 봐야 합니다. 이때 가장 많이 놓치는 값이 keyboardVerticalOffset입니다.

keyboardVerticalOffset은 화면 최상단과 현재 React Native 뷰 사이에 이미 확보된 거리만큼 보정해주는 역할을 합니다. 예를 들어 상단 헤더가 있거나 네비게이션 영역 때문에 콘텐츠 시작점이 내려와 있다면, 키보드 회피 계산도 그만큼 맞춰줘야 움직임이 덜 어색해집니다. 숫자를 외우기보다 현재 화면에서 이미 차지하고 있는 상단 높이를 기준으로 생각하면 훨씬 덜 헷갈립니다.

offset과 ScrollView를 함께 쓰는 예시

import { KeyboardAvoidingView, Platform, ScrollView, TextInput, Pressable, Text} from 'react-native'; export default function SignupScreen() { return ( <KeyboardAvoidingView // iOS와 Android는 behavior 체감이 다르므로 둘을 분리해서 시작합니다. behavior={Platform.OS === 'ios' ? 'padding' : undefined} keyboardVerticalOffset={64} style={{ flex: 1 }} > <ScrollView // 긴 입력 폼에서는 내부 스크롤이 함께 움직여야 훨씬 안정적입니다. contentContainerStyle={{ padding: 24, gap: 12 }} keyboardShouldPersistTaps="handled" > <TextInput placeholder="이름" /> <TextInput placeholder="이메일" /> <TextInput placeholder="전화번호" keyboardType="phone-pad" /> <TextInput placeholder="자기소개" multiline style={{ minHeight: 120 }} /> <Pressable> <Text>가입하기</Text> </Pressable> </ScrollView> </KeyboardAvoidingView> );
}

입력 항목이 2~3개 정도라면 ScrollView 없이도 충분할 수 있습니다. 하지만 회원가입, 문의 작성, 프로필 수정처럼 길어지는 폼은 대부분 ScrollView와 같이 써야 안정적입니다. 특히 키보드가 올라온 상태에서 다음 입력창이나 버튼을 누를 일이 많기 때문에 keyboardShouldPersistTaps를 함께 보는 편이 좋습니다.

또 하나 기억할 점은 가 입력창을 자동으로 스크롤해 주는 도구는 아니라는 점입니다. 화면이 짧고 입력이 적을 때는 충분하지만, 입력 필드가 많아질수록 내부 스크롤과 조합해서 봐야 기대한 UX가 나옵니다. 그래서 긴 폼일수록 “레이아웃 회피”와 “스크롤 이동”을 같이 생각하는 편이 맞습니다.

자주 막히는 문제와 점검 포인트

Expo KeyboardAvoidingView 사용법: 키보드 가림 해결 적용 흐름을 설명하는 두 번째 본문 이미지

실무에서 가장 흔한 오해는 를 넣었는데도 입력창이 가려지면 이 컴포넌트가 고장났다고 판단하는 것입니다. 실제로는 감싼 범위가 너무 작거나, 부모에 flex: 1이 없거나, ScrollView와 하단 고정 버튼 구조가 충돌하거나, Android 쪽 키보드 레이아웃 정책 때문에 생기는 경우가 더 많습니다.

Android Bottom Tab에서 탭이 같이 밀릴 때

{ "expo": { "android": { // Bottom Tab이 키보드 위로 밀려 올라오는 현상을 줄이기 위한 설정입니다. "softwareKeyboardLayoutMode": "pan" } }
}

Expo에서 Bottom Tab navigator를 쓰는 Android 화면은 입력창에 포커스가 갈 때 탭 바가 키보드 위로 같이 밀려 보이는 경우가 있습니다. 이럴 때는 app.json 또는 app.config에서 softwareKeyboardLayoutMode를 pan으로 두는 방법을 먼저 확인하는 편이 좋습니다. 필요하다면 탭 자체를 키보드가 열릴 때 숨기는 방식도 같이 검토할 수 있습니다.

탭을 숨기거나 하단 여백을 따로 계산하는 방식

<Tabs screenOptions={{ // 키보드가 열릴 때 탭 바를 숨기는 대안입니다. tabBarHideOnKeyboard: true}}
/> // 탭 바를 absolute로 띄운 경우에는 하단 여백을 직접 더해야 할 수 있습니다.
const tabBarHeight = useBottomTabBarHeight(); <ScrollView contentContainerStyle={{ paddingBottom: tabBarHeight }} />

Expo 공식 가이드는 Android 탭 문제의 대안으로 tabBarHideOnKeyboard도 함께 안내합니다. 또한 React Navigation 문서는 탭 바를 position: ‘absolute’로 두면 콘텐츠 하단 여백을 자동으로 계산해주지 않으므로, useBottomTabBarHeight 같은 방식으로 직접 보정해야 한다고 설명합니다. 즉, 현재 문제를 단순히 키보드 회피만의 문제로 볼 것이 아니라, 탭 바 배치 방식까지 포함해서 판단하는 편이 더 정확합니다.

이상하게 안 움직일 때 먼저 볼 것

<KeyboardAvoidingView style={{ flex: 1 }}> <ScrollView contentContainerStyle={{ flexGrow: 1, padding: 24 }}> {/* 부모 높이와 내부 스크롤 구조를 먼저 확인합니다. */} </ScrollView>
</KeyboardAvoidingView>

효과가 없는 것처럼 보일 때는 behavior부터 바꾸기 전에 구조를 먼저 보는 편이 좋습니다. 부모에 flex: 1이 빠져 있으면 높이 계산이 제대로 되지 않을 수 있고, 하단 고정 버튼이 별도 absolute 구조로 떠 있다면 입력창은 올라왔는데 버튼은 그대로 가려지는 상황도 생길 수 있습니다. 이런 경우는 의 문제가 아니라 레이아웃 배치 방식의 문제에 가깝습니다.

정리

는 입력창이 키보드에 가려지는 문제를 줄이기 위한 가장 기본적인 출발점입니다. 다만 실무에서는 behavior 선택, keyboardVerticalOffset 보정, ScrollView 조합, Android 키보드 정책까지 함께 봐야 비로소 원하는 움직임이 나옵니다.

정리하면 이렇게 접근하는 편이 편합니다. 짧은 폼은 부터 적용하고, 긴 폼은 ScrollView와 함께 보며, Android 탭 이슈가 있으면 softwareKeyboardLayoutMode와 탭 표시 정책까지 같이 점검합니다. 화면이 더 복잡해지면 기본 컴포넌트만으로 해결하려고 버티기보다, 입력 수가 많은 폼에 맞는 대안을 검토하는 편이 오히려 빠를 수 있습니다.

많이 받는 질문

Q. 이 컴포넌트만 넣으면 모든 입력 화면 문제가 해결되나요?
아닙니다. 짧은 폼에서는 잘 맞을 수 있지만, 긴 폼이나 하단 고정 버튼, 탭 네비게이션이 섞인 화면은 ScrollView, offset, Android 설정까지 함께 봐야 자연스럽습니다.

Q. Android에서는 behavior를 무엇으로 시작하는 편이 좋나요?
Expo 가이드 예시처럼 Android에서는 undefined로 시작해보고, 화면 구조에 따라 height나 position을 비교해보는 흐름이 무난합니다. iOS에서 잘 맞는 padding이 Android에서 같은 느낌을 주지 않을 수 있기 때문입니다.

Q. keyboardVerticalOffset은 어떻게 정하면 되나요?
헤더나 상단 고정 영역 때문에 실제 콘텐츠 시작 위치가 아래로 내려와 있다면, 그 높이만큼 보정한다고 이해하면 됩니다. 숫자를 외우기보다 현재 화면 구조를 보고 조정하는 방식이 더 실무적입니다.

Q. 탭 바가 absolute로 떠 있으면 만으로 충분한가요?
항상 그렇지는 않습니다. React Navigation 문서 기준으로 absolute 탭 바는 콘텐츠 하단 여백을 자동으로 보정하지 않기 때문에, useBottomTabBarHeight 등으로 paddingBottom을 추가로 계산해야 하는 경우가 있습니다.

같이 읽으면 좋은 글

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

댓글 남기기