EdgeToEdge UI 가 적용된 액티비티에서는
windowSoftInputMode="adjustResize" 설정이 적용되지 않습니다.
앱을 개발하다보면 회원가입, 게시글 작성 등 사용자 입력을 받는 화면을 구현할 경우가 있습니다.
입력받을 항목이 많다면 한 화면을 모두 사용하여 뷰를 배치하거나 스크롤뷰를 사용하게 됩니다. 이때 사용자 입력을 위해 EditText 나 머티리얼의 TextInputLayout 을 사용하게 되는데 글씨를 입력 하기 위해 소프트키보드가 밑에서 올라오게 됩니다. 화면의 상단에 배치한 입력용 뷰들은 크게 문제는 없지만 화면 하단에 배치한 EditText는 소프트키보드에 의해 가려지게 됩니다.
이럴 때 해결방법 중 하나가 activity에게 설정하는 android:windowSoftInputMode="adjustResize" 입니다. 많이 알려진 방법으로서 소프트키보드가 올라오면 액티비티의 사이즈를 남은 공간만큼 줄여줘서 입력뷰가 가려지지 않도록 하는 속성입니다.
AndroidManfest.xml
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
하지만 EdgeToEdge UI 가 적용된 액티비티에서는 위 "adjustResize" 설정값이 적용되지 않습니다.
EdgeToEdge UI 에서는 시스템바(status bar, navigation bar) 영역에 뷰가 가려지지 않도록 동적으로 padding 을 적용하는 코드에 의해 adjustResize 설정값을 무시합니다.
♣ 해결방법
EdgeToEdge UI 에서는 시스템바와 같은 Insets 들의 사이즈를 동적으로 얻어와서 패딩을 통해 뷰들이 가려지지 않도록 하는 방법을 권장합니다.
Inset
큰 그림안에 있는 작은 그림이나 조각 같은 것을 나타냅니다.
Android에서 "Insets"는 화면의 일부를 차지하는 시스템 UI 요소(예: 상태 바, 내비게이션 바, 키보드 등) 입니다.
주요 Android Insets 종류
statusBars() | 상단의 상태바(Status Bar) 영역 |
navigationBars() | 하단 또는 측면의 내비게이션 바(Navigation Bar) 영역 |
ime() | **소프트 키보드(IME)**가 차지하는 영역 |
systemBars() | statusBars + navigationBars 의 조합 |
captionBar() | 다이얼로그 또는 일부 윈도우에 있는 캡션 바 영역 |
displayCutout() | 노치(notch) 또는 카메라 홀 등 디스플레이 컷아웃 영역 |
tappableElement() | 시스템 제스처(예: 뒤로가기 등)에 방해되지 않아야 하는 탭 가능한 영역 |
mandatorySystemGestures() | 사용자가 필수 시스템 제스처를 수행하는 영역 |
systemGestures() | 일반 시스템 제스처 영역 (예: 풀스크린 제스처) |
waterfall() | 디스플레이 가장자리의 워터폴(edge) 스크린 영역 |
현재 소프트키보드에 의해 가려지는 TextInput 뷰를 해결하기 위해서는 ime() Insets 를 얻어와서 키보드의 높이만큼 아래쪽에 패딩을 적용하여 가려지지 않도록 만들어야 합니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
//시스템바의 insets
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
//소프트키보드의 insets
val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime())
//소프트키보드가 없다면( bottom 좌표가 0 ) 시스템바 사이즈 만큼만 아래(bottom) 영역을 주고 있다면 소프트키보드의 높이만큼 아래(bottom) 패딩 지정.
if(imeInsets.bottom==0) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
else v.setPadding(systemBars.left, systemBars.top, systemBars.right, imeInsets.bottom)
insets
}
}
}
이제 소프트 키보드가 올라오면 그만큼 액티비티의 아래쪽 패딩이 주어지게 되어 뷰들이 소프트키보드 영역에 가려지는 문제가 발생하지 않게 됩니다. 단, 스크롤뷰를 사용하지 않았다면 단순이 뷰들이 놓여지는 액티비티의 영역이 작아지는 것이기에 아래쪽의 뷰들을 볼 수 없게 되니 스크롤뷰로 입력창들을 감싸도록 해줘야 합니다.