[Android/Compose] Window Insets을 Compose에서 다루는 방법

Falco·2023년 3월 7일
2

Android

목록 보기
39/55
post-custom-banner

Problem

어플리케이션에서 키보드는 빼놓을 수 없는 요소이다.
그런 키보드의 상태에 따라 뷰에 변화를 주고싶다.

(키보드가 올라옴에 따라 인증 문자 요청 버튼이 위에 따라 올라옴)


해당 문제를 해결하기전에 WindowInsets에 대해 알고 가면 좋을 것 같다.

WindowInsets-Android Developer

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가 있다.

  • System window insets
SystemWindowInsets: Insets{left=0, top=66, right=0, bottom=66}   
상태바와 네비게이션 바의 높이를 표현한다.

  • Tappable element insets
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 를 제외하고는 모두 탭이 가능하다.
  • Gesture insets
systemGestures=Insets{left=82, top=66, right=82, bottom=88} 
시스템 제스쳐에 관련된 범위를 표현한다. (ex 뒤로가기, 메뉴창, 앞으로가기 등등..)

  • Stable insets
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은 상태 표시줄과 관련된 패딩을 계속 제공한다.

Solution

이런 windownInsets 내부의 패딩 값 중 ime를 활용해 키보드가 올라왔을 때 버튼을 올릴 수 있다.

IME이란 Input Method Editor를 뜻한다. (즉 키보드 크기)

일단 이런 패딩을 적용시키기 전에

WindowCompat.setDecorFitsSystemWindows(window, false)

decorateFitSystemWindowsfalse로 등록해야 한다.

해당 값을 설정하면 프레임워크가 content viewinsets에 맞추지 않고 WindowInsetsCompat를 통해 content view로 전달한다.

WindowInsets는 루트 뷰에서 자식 뷰로 전달되는데, 중간에 conumse을 받게되면 자식 뷰들은 WindowInsets 이벤트를 받지 못하게 된다. 기본설정은 true인데 이러면 안드로이드 기본값 insets를 적용하면서 conumse을 받는다. (별도 설정 없이 앱을 실행시켰을 때 UI가 시스템 영역에 가려지지 않는 이유가 이것이다.)

네이버 지도의 같은 경우는 setDecorFitsSystemWindowsfalse로 지정 하여 바텀 네비게이션바와 스테이터스바까지 뷰가 그려지도록 하고 있다.

WindowInsets를 활용한 패딩 적용시키기

컴포즈 이전에서는 WindowInsetsAnimationCallback를 활용해 어플리케이션이 insets에 대한 애니메이션 이벤트를 수신하고, 직접 padding값을 수정해줘야 했다.

하지만 Compose에서는 이러한 WindowInsetsModifier를 활용해 사용할 수 있음으로 아주 쉽게 사용할 수 있다.

 Column(
        modifier = Modifier
            .fillMaxSize()
            .systemBarsPadding()
            .imePadding()
    ) {
	
        // 해당 Column 이후부터는 자동으로 imePadding을 적용시킨다.
        // -> imePadding을 Consume한다.
    
	}        

WindowInsetsInsets가 한번 사용되면 중복 적용을 방지하기 위해 자동으로 해당 Insetsconsume된다. (패딩이 애니메이션에 따라 적용됨)

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)

Jetpack Compose + WindowInsets = 🤩 🥳

System Gesture

profile
강단있는 개발자가 되기위하여
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 11월 14일

좋은 글 감사합니다~

답글 달기