이제 몇 가지 기본 애니메이션 API에 익숙해졌으므로 더 복잡한 애니메이션을 만들 수 있는 Transition API를 살펴보자. 이 예에서는 탭 인디케이터를 커스터마이징 한다. 이는 현재 선택된 탭에 표시되는 사각형이다.

HomeTabIndicator 컴포저블에서 TODO 4를 찾아 탭 인디케이터가 어떻게 구현되는지 확인해보자.

val indicatorLeft = tabPositions[tabPage.ordinal].left
val indicatorRight = tabPositions[tabPage.ordinal].right
val color = if (tabPage == TabPage.Home) Purple700 else Green800

여기서 IndicatorLeft는 탭 행(tab row)에서 인디케이터의 왼쪽 테두리고, IndicatorRight는 인디케이터의 오른쪽 테두리다. 색상도 보라색과 녹색 사이에서 변경된다.

이러한 여러 값을 동시에 애니메이션하기 위해 Transition을 사용할 수 있다. updateTransition 함수로 트랜지션을 생성할 수 있다. targetState 매개변수로 현재 선택된 탭의 인덱스를 전달한다.

각 애니메이션 값은 Transition의 animate* 확장 함수로 선언될 수 있다. 이 예제에서는 animateDp 및 animateColor를 사용한다. 그것들은 람다 블록을 사용하고, 우리는 각 상태에 대한 목표 값을 지정할 수 있다. 목표 값이 무엇인지 이미 알고 있으므로 아래와 같이 값을 간단히 래핑할 수 있다. animate* 함수가 State 객체를 반환하기 때문에 여기에서 by 선언을 사용하고, 이를 다시 local delegated property 만들 수 있다.

val transition = updateTransition(tabPage)
val indicatorLeft by transition.animateDp { page ->
    tabPositions[page.ordinal].left
}
val indicatorRight by transition.animateDp { page ->
    tabPositions[page.ordinal].right
}
val color by transition.animateColor { page ->
    if (page == TabPage.Home) Purple700 else Green800
}

지금 앱을 실행하면 훨씬 더 흥미롭다는 탭 전환이 되는 것을 알 수 있다. 탭을 클릭해 tabPage 상태 값이 변경됨에 따라, 전환과 관련된 모든 애니메이션 값이 대상 상태에 대해 지정된 값으로 애니메이션 되기 시작한다.

3262270d174e77bf.gif

또한, transitionSpec 매개변수를 지정하여 애니메이션 동작을 커스터마이징 할 수 있다. 예를 들어, 목적지에 더 가까운 가장자리가 다른 가장자리보다 빠르게 움직이도록 함으로써 인디케이터에 대한 탄성 효과를 얻을 수 있다. transitionSpec 람다에서 isTransitioningTo infix 함수를 사용하여 상태 변경 방향을 결정할 수 있다.

val transition = updateTransition(
    tabPage,
    label = "Tab indicator"
)
val indicatorLeft by transition.animateDp(
    transitionSpec = {
        if (TabPage.Home isTransitioningTo TabPage.Work) {
            // 인디케이터가 오른쪽으로 이동한다.
            // 왼쪽 엣지가 오른쪽 엣지보다 천천히 이동한다.
            spring(stiffness = Spring.StiffnessVeryLow)
        } else {
            // 인디케이터가 왼쪽으로 이동한다.
            // 왼쪽 엣지가 오른쪽 엣지보다 빠르게 이동한다.
            spring(stiffness = Spring.StiffnessMedium)
        }
    },
    label = "Indicator left"
) { page ->
    tabPositions[page.ordinal].left
}
val indicatorRight by transition.animateDp(
    transitionSpec = {
        if (TabPage.Home isTransitioningTo TabPage.Work) {
            // 인디케이터가 오른쪽으로 이동한다.
            // 오른쪽 엣지가 왼쪽 엣지보다 빠르게 이동한다.
            spring(stiffness = Spring.StiffnessMedium)
        } else {
            // 인디케이터가 왼쪽으로 이동한다.
            // 오른쪽 엣지가 왼쪽 엣지보다 느리게 이동한다.
            spring(stiffness = Spring.StiffnessVeryLow)
        }
    },
    label = "Indicator right"
) { page ->
    tabPositions[page.ordinal].right
}
val color by transition.animateColor(
    label = "Border color"
) { page ->
    if (page == TabPage.Home) Purple700 else Green800
}

앱을 다시 실행하고 탭을 전환해 보자.

2ad4adbefce04ae2.gif

Android Studio는 컴포즈 Preview에서 전환 검사를 지원한다. 애니메이션 미리보기를 사용하려면, 미리보기에서 컴포저블의 오른쪽 상단 모서리에 있는 “Start interactive mode” 아이콘을 클릭하여 인터렉티브 모드를 시작한다. 아이콘을 찾을 수 없는 경우 여기에 설명된 대로 실험실 설정에서 이 기능을 활성화해야 한다. PreviewHomeTabBar 컴포저블 아이콘을 클릭해 보자. 그런 다음 인터렉티브 모드의 오른쪽 상단 모서리에 있는 “Start animation inspection” 아이콘을 클릭한다. 그러면 새 “Animations” 창이 열린다.

“Play” 아이콘 버튼을 클릭하여 애니메이션을 실행할 수 있다. seekbar를 드래그해 각 애니메이션 프레임을 볼 수도 있다. 애니메이션 값에 대한 더 나은 설명을 위해 updateTransitionanimate* 메서드에서 label 매개변수를 지정할 수 있다.

2d3c5020ae28120b.png
카테고리: Compose

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.