어플리케이션에서 키보드는 빼놓을 수 없는 요소이다.
그런 키보드의 상태에 따라 뷰에 변화를 주고싶다.
(키보드가 올라옴에 따라 인증 문자 요청 버튼이 위에 따라 올라옴)
해당 문제를 해결하기전에 WindowInsets
에 대해 알고 가면 좋을 것 같다.
Describes a set of insets for window content.
윈도우 콘텐츠에 대한 Insets
을 정의한다고 한다.
Insets
는 네 모서리의 크기를 가지고 있는 객체이다.그렇다면 직접 WindowInsets
에 어떤 속성이 들어가있는지 확인해보자.
WindowInsets: WindowInsets{
statusBars=Insets{left=0, top=66, right=0, bottom=0}
bottom=0} vis=true
navigationBars=Insets{left=0, top=0, right=0, bottom=66}
ime=Insets{left=0, top=0, right=0, bottom=0} max=null vis=false
systemGestures=Insets{left=82, top=66, right=82, bottom=88}
mandatorySystemGestures=Insets{left=0, top=66, right=0, bottom=88}
tappableElement=Insets{left=0, top=66, right=0, bottom=0}
// ...
}
WindowInsets에는 다음과 같은 총 4가지의 Insets가 있다.
SystemWindowInsets: Insets{left=0, top=66, right=0, bottom=66}
상태바와 네비게이션 바의 높이를 표현한다.
tappableElement=Insets{left=0, top=66, right=0, bottom=0}
The tappable element insets represent how much tappable elements must at least be inset to remain both
tappable and visually unobstructed by persistent system windows.
시스템 창에 의해 방해받지 않고 탭 가능한 상태를 유지하기 위해 필요한 Insets
즉 top=66 를 제외하고는 모두 탭이 가능하다.
systemGestures=Insets{left=82, top=66, right=82, bottom=88}
시스템 제스쳐에 관련된 범위를 표현한다. (ex 뒤로가기, 메뉴창, 앞으로가기 등등..)
The stable inset represents the area of a full-screen window
that may be partially or fully obscured by the system UI elements.
Stable Insets은 시스템 UI 요소에 의해 부분적으로
또는 완전히 가려질 수 있는 전체 화면 창의 영역을 나타낸다.
This value does not change based on the visibility state of those elements; for example, if the status bar is normally shown,
but temporarily hidden, the stable inset will still provide the inset associated with the status bar being shown.
이 값은 가시성 상태에 따라 변경되지 않는다.
예를 들어, 상태 표시줄이 표시되든, 가려져 있는 stable insets은 상태 표시줄과 관련된 패딩을 계속 제공한다.
이런 windownInsets
내부의 패딩 값 중 ime
를 활용해 키보드가 올라왔을 때 버튼을 올릴 수 있다.
IME이란 Input Method Editor를 뜻한다. (즉 키보드 크기)
일단 이런 패딩을 적용시키기 전에
WindowCompat.setDecorFitsSystemWindows(window, false)
decorateFitSystemWindows
를 false
로 등록해야 한다.
해당 값을 설정하면 프레임워크가 content view
를 insets
에 맞추지 않고 WindowInsetsCompat
를 통해 content view
로 전달한다.
WindowInsets
는 루트 뷰에서 자식 뷰로 전달되는데, 중간에 conumse
을 받게되면 자식 뷰들은 WindowInsets
이벤트를 받지 못하게 된다. 기본설정은 true
인데 이러면 안드로이드 기본값 insets
를 적용하면서 conumse
을 받는다. (별도 설정 없이 앱을 실행시켰을 때 UI
가 시스템 영역에 가려지지 않는 이유가 이것이다.)
네이버 지도의 같은 경우는
setDecorFitsSystemWindows
을false
로 지정 하여 바텀 네비게이션바와 스테이터스바까지 뷰가 그려지도록 하고 있다.
컴포즈 이전에서는 WindowInsetsAnimationCallback
를 활용해 어플리케이션이 insets
에 대한 애니메이션 이벤트를 수신하고, 직접 padding
값을 수정해줘야 했다.
하지만 Compose
에서는 이러한 WindowInsets
를 Modifier
를 활용해 사용할 수 있음으로 아주 쉽게 사용할 수 있다.
Column(
modifier = Modifier
.fillMaxSize()
.systemBarsPadding()
.imePadding()
) {
// 해당 Column 이후부터는 자동으로 imePadding을 적용시킨다.
// -> imePadding을 Consume한다.
}
WindowInsets
는 Insets
가 한번 사용되면 중복 적용을 방지하기 위해 자동으로 해당 Insets
이 consume
된다. (패딩이 애니메이션에 따라 적용됨)
val NavigationBarHeightDp
@Composable
get() = with(LocalDensity.current) {
WindowInsets.systemBars.getBottom(this).toDp()
}
val StatusBarHeightDp
@Composable
get() = with(LocalDensity.current) {
WindowInsets.systemBars.getTop(this).toDp()
}
패딩을 바로 적용시키는 것이 아니라, 사이즈만 단독으로 얻어올 수도 있다.
이런 imePadding
뿐만 아니라 추가적인 여러 패딩도 제공하고 있다.
Modifier.mandatorySystemGesturesPadding()
Modifier.systemGesturesPadding()
Modifier.waterfallPadding()
Modifier.captionBarPadding()
Modifier.navigationBarsPadding()
Modifier.imePadding()
Modifier.statusBarsPadding()
Modifier.displayCutoutPadding()
Modifier.systemBarsPadding()
Android Developer - Modifier 상세 정보
안드로이드 WindowInsets으로 키보드 애니메이션 구현하기 (1)
좋은 글 감사합니다~