CoordinatorLayout

#Android #Android_Animation

1. CoordinatorLayout

CoordinatorLayout은 CoordinatorLayout의 자식뷰들간에 서로의 레이아웃 변화 상태를 공유하게 해주는 레이아웃이다.

예를들어, 웹툰이나 미디어앱에서 리스트를 스크롤하면 스크롤에 따라 위에 있던 카테고리바가 올라가면서 리스트 뷰가 위에 붙는것을 종종 볼 수 있는데, 이것은 리스트뷰(리사이클러뷰)의 움직임과 상태를 카테고리바(탭바)가 공유받아서 위치를 조정하게 되는것으로 이것이 CoordinatorLayout의 구현 예이다.

+ CoordinatorLayout은 FrameLayout을 상속받아 구현되었다.


2. CoordinatorLayout의 요소

CoordinatorLayout은 자식뷰들간에 상태를 공유할 수 있게 해준다고 했다. 어떻게?

CoordinatorLayout이 모든 자식뷰에서 발생하는 이벤트를 관찰하고 있을까? 아니다. "어떤 뷰를 관찰해주세요."라는 부탁과 "관찰할만한 행동이 포착되면 이렇게 해주세요."라는 요청을 받아야 관찰하고 행동을 한다. 그러면 이런 부탁과 요청사항을 할 수 있도록 하는 무언가는 무엇일까?

2-1. Behavior

CoordinatorLayout에게 다른 형제뷰의 이벤트에 대한 관찰과 그 결과에 대한 동작을 명세해놓은 클래스이다. 위에서 얘기한 "어떤 뷰를 관찰해주세요."와 "행동이 포착되면 이렇게 해주세요."를 정의해놓은 것이다. 아래의 예시처럼 CoordinatorLayout.Behavior<V>(context, attrs)를 상속받아서 구현한다.

layoutDependsOn()은 "어떤 뷰를 관찰해주세요."에 대한 정의이며, onDependentViewChanged()는 "관찰시에 행동이 포착되면 이렇게 해주세요."에 대한 구현이다.

class CustomBehavior<V : View>(context: Context, attrs: AttributeSet) :
    CoordinatorLayout.Behavior<V>(context, attrs) {

    override fun layoutDependsOn(
        parent: CoordinatorLayout,
        child: V,
        dependency: View
    ): Boolean {
        // 특정 뷰에 종속적 동작을 정의
        return dependency is AppBarLayout
    }

    override fun onDependentViewChanged(
        parent: CoordinatorLayout,
        child: V,
        dependency: View
    ): Boolean {
        // 종속된 뷰의 변경 사항에 반응
        child.translationY = -dependency.y
        return true
    }
}

2-2. Anchor

어떤 뷰의 위치가 변경될 때에 그에 따라 해당 뷰의 상대적 위치를 잡고 싶을 때 사용한다. 예를들어, BottomSheet에 우측 상단에 걸쳐있는 FloatingButton이 BottomSheet가 위로 올라가던 내려가던 BottomSheet 우측 상단에 그대로 위치하게 하고 싶을 때 사용할 수 있는 것이다. (참고 - Android Anchoring Views to Bottom Sheet, Emrullah Lüleci)

2-3. 참고


3. CollapsingToolbarLayout

대부분이 CoordinatorLayout을 접하게 된 경로가 아닐까 싶다. 처음엔 CollapsingToolbarLayout이 CoordinatorLayout이랑 한 쌍처럼 느껴져서 CoordinatorLayout은 CollapsingToolbarLayout을 위해서만 사용되고 그 반대의 경우도 마찬가지인줄 알았다. 하지만, CollapsingToolbarLayout은 CoordinatorLayout을 사용하는 대표적인 하나의 경우일 뿐이라는것.

CollapsingToolbarLayout은 Appbar내에서 스크롤에 따라 접히고 펼쳐지는 뷰를 말한다.

3-1. CollapsingToolbarLayout의 구조

박서현님의 블로그(CollapsingToolbarLayout으로 움직이는 상단바 만들기, 박서현)의 이미지구조 사진을 통해 레이아웃 구조를 한번에 이해할 수 있었다. 스크롤업 할 때 어떤것이 남고 없어지는지, 다시 스크롤 다운할 때 어떤것이 살아나는지 상상해보면 좋다.
+ 이 블로그에서 layout_scrollFlags 속성에 대해서도 잘 이해할 수 있다.

3-2. appbar_scrolling_view_behavior

NestedScrollView나 ViewPager등의 속성으로 app:layout_behavior="@string/appbar_scrolling_view_behavior"을 사용한다. 이것은 Appbar 클래스에서 CollapsingToolbarLayout을 위해 만들어둔 static class로 appbar의 레이아웃이 변경될 때 이웃 뷰에 어떤 영향을 줄지에 대한 정의이다. (참고 - AppBarLayout.java source code)

3-3. 참고


4. Compose Migration

Android Doc - Migrate CoordinatorLayout to Compose

CoordinatorLayout을 Compose로 Migration하기 위해서 고려해야할 것들이 몇가지 있다. 이것은 다른 View를 Compose로 Migration하는 전략에도 적용되는데, View를 유지하고 Compose의 AndroidView를 사용할 것인지, Fragment만 유지하고 그 안에 ComposeView를 선언할 것인지, 모든것을 Compose로 만들것인지에 관한 것이다. (참고 - Compose Migration 전략)

위의 결정사항에서 CoordinatorLayout가 감싸고 있는 View 모두를 Compose로 전환하기로 했다면 안드로이드 도큐먼트는 Compose의 Scaffold를 이용해서 Migration할 수 있다고 설명하고 있다. CollapsingToolbarLayout부터 Drawer, Snackbar에 대한 예제까지 보여주고 있으니 참고하면 좋을 것이다.


5. Use Case (feat. MotionLayout)

원래는 MotionLayout을 알아보고있다가 여기까지 오게되었다. CoordinatorLayout을 사용해본 경험은 있지만 이것이 MotionLayout과 어떻게 다르고 조금 더 자유롭게 사용할 수 있도록 정리해보자!라는 마음에서 포스팅을 하게되었다. 그러면 어떨 때 MotionLayout을 사용하고 어떨 때 CoordinatorLayout을 사용해야할까? (괄호로 GPT의 답변을 추가하도록 한다.)

거의 모든 개발이 그렇지만 필수적으로 어떤것을 사용해야 한다.라기 보다는 경우에 따라 더 편리한 방법이 있는것이기에 감안하고 봐주셨으면 한다.

우선 CoordinatorLayout은 스크롤, 스와이프등의 동작 상태를 형제뷰와 공유하여 형제뷰의 위치와 모양 크기등을 조절할 수 있도록 만들어진 레이아웃이다. 복잡한 상황보다는 심플하게 움직이고 심플하게 변경해야하는 요청사항이 있을 때 사용할 것 같다. (CoordinatorLayout은 뷰 간의 상호작용과 의존성을 다루는 데 적합하며, 주로 스크롤 중심의 동작을 처리합니다.)

반면에 MotionLayout의 경우에는 화면이 전환된다던지, 뷰의 속성을 시간에 따라 변경시켜야 한다던지의 과정에서 사용된다. (형제뷰와 형제뷰가 자신들의 상태를 공유하면서 변경된다기 보다는 각각의 뷰가 변경될 때의 상태를 정의함.) 예를들어, 애니메이션의 시작과 끝을 정의하여 그 과정에서 색상변화, 위치 플로우 설정등을 명세하는 것이다. 틀에 얽매이지 않는 매우 다양한 Transition을 구현할 때 사용된다. (MotionLayout은 복잡한 애니메이션과 전환 효과를 구현하는 데 적합하며, 상태 기반의 세밀한 제어가 가능합니다.)

(