MotionLayout으로 모션 및 위젯 애니메이션 관리

MotionLayout는 앱에서 모션과 위젯 애니메이션을 관리하는 데 도움이 되는 레이아웃 유형입니다. MotionLayoutConstraintLayout의 서브클래스이며 풍부한 레이아웃 기능을 기반으로 합니다. ConstraintLayout 라이브러리의 일부로 MotionLayout를 지원 라이브러리로 사용할 수 있습니다.

MotionLayout는 레이아웃 전환과 복잡한 모션 처리 간의 격차를 줄여 속성 애니메이션 프레임워크, TransitionManagerCoordinatorLayout 간의 혼합 기능을 제공합니다.

그림 1. 기본 터치 컨트롤 모션

레이아웃 간의 전환을 설명하는 것 외에도 MotionLayout를 사용하면 모든 레이아웃 속성에 애니메이션을 적용할 수 있습니다. 또한 기본적으로 검색 가능한 전환을 지원합니다. 즉, 터치 입력과 같은 일부 조건에 따라 전환 내의 원하는 지점을 즉시 표시할 수 있습니다. MotionLayout는 키프레임도 지원하므로 필요에 맞게 완전히 맞춤설정된 전환을 사용할 수 있습니다.

MotionLayout는 완전히 선언적입니다. 즉, 아무리 복잡하더라도 XML에서 모든 전환을 설명할 수 있습니다.

설계 고려사항

MotionLayout는 사용자가 상호작용하는 버튼, 제목 표시줄 등 UI 요소를 이동하고 크기를 조절하고 애니메이션 처리하기 위한 것입니다. 앱에서 모션을 불필요한 특수 효과로 사용하지 마세요. 이를 통해 사용자가 앱의 기능을 이해할 수 있도록 도와주세요. 모션을 사용하여 앱을 디자인하는 방법에 관한 자세한 내용은 Material Design 섹션 모션 이해를 참고하세요.

시작하기

프로젝트에서 MotionLayout 사용을 시작하려면 다음 단계를 따르세요.

  1. ConstraintLayout 종속 항목 추가: 프로젝트에서 MotionLayout를 사용하려면 앱의 build.gradle 파일에 ConstraintLayout 2.0 종속 항목을 추가합니다. AndroidX를 사용하는 경우 다음 종속 항목을 추가합니다.

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha13"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13"
    }
    

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha13")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13")
    }
    
  2. MotionLayout 파일 만들기: MotionLayoutConstraintLayout의 서브클래스이므로 다음 예와 같이 레이아웃 리소스 파일에서 클래스 이름을 바꿔 기존 ConstraintLayoutMotionLayout로 변환할 수 있습니다.

    AndroidX

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    지원 라이브러리

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    다음은 그림 1에 표시된 레이아웃을 정의하는 MotionLayout 파일의 전체 예입니다.

    AndroidX

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </androidx.constraintlayout.motion.widget.MotionLayout>
            

    지원 라이브러리

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <android.support.constraint.motion.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </android.support.constraint.motion.MotionLayout>
            
  3. MotionScene 만들기: 이전 MotionLayout 예에서 app:layoutDescription 속성은 모션 장면을 참조합니다. 모션 장면은 XML 리소스 파일입니다. <MotionScene> 루트 요소 내의 모션 장면에는 상응하는 레이아웃의 모든 모션 설명이 포함됩니다. 레이아웃 정보를 모션 설명과 별도로 유지하기 위해 각 MotionLayout는 별도의 모션 장면을 참조합니다. 모션 장면의 정의는 MotionLayout의 유사한 정의보다 우선합니다.

    다음은 그림 1의 기본 수평 모션을 설명하는 모션 장면 파일의 예입니다.

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">
    
        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>
    
        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
    </MotionScene>
        

    다음 내용을 참고하세요.

    • <Transition>에는 모션의 기본 정의가 포함됩니다.

      • motion:constraintSetStartmotion:constraintSetEnd는 모션의 엔드포인트 참조입니다. 이러한 엔드포인트는 모션 장면 후반부의 <ConstraintSet> 요소에 정의됩니다.

      • motion:duration는 모션이 완료되는 데 걸리는 시간(밀리초)을 지정합니다.

    • <OnSwipe>를 사용하면 모션의 터치 컨트롤을 만들 수 있습니다.

      • motion:touchAnchorId는 사용자가 스와이프하고 드래그할 수 있는 뷰를 나타냅니다.

      • motion:touchAnchorSide은 뷰가 오른쪽에서 드래그되고 있음을 의미합니다.

      • motion:dragDirection는 드래그의 진행 방향을 나타냅니다. 예를 들어 motion:dragDirection="dragRight"는 뷰를 오른쪽으로 드래그하면 진행률이 증가한다는 의미입니다.

    • <ConstraintSet>에서는 모션을 설명하는 다양한 제약 조건을 정의합니다. 이 예에서는 모션의 각 엔드포인트에 하나의 <ConstraintSet>가 정의되어 있습니다. 이러한 엔드포인트는 app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"를 사용하여 세로로 가운데에 배치됩니다. 가로로 봤을 때 엔드포인트는 화면의 맨 왼쪽과 오른쪽에 있습니다.

    모션 장면에서 지원하는 다양한 요소에 관한 자세한 내용은 MotionLayout 예를 참고하세요.

보간된 속성

모션 장면 파일 내 ConstraintSet 요소에는 전환 중에 보간되는 추가 속성이 포함될 수 있습니다. 위치 및 경계 외에도 다음 속성이 MotionLayout로 보간됩니다.

  • alpha
  • visibility
  • elevation
  • rotation, rotationX, rotationY
  • translationZ translationY translationX
  • scaleY scaleX

맞춤 속성

<Constraint> 내에서 <CustomAttribute> 요소를 사용하여 위치 또는 View 속성과 관련 없는 속성의 전환을 지정할 수 있습니다.

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

<CustomAttribute>에는 다음과 같은 두 가지 고유 속성이 있습니다.

  • motion:attributeName는 필수 항목이며 getter 및 setter 메서드가 있는 객체와 일치해야 합니다. getter와 setter는 특정 패턴과 일치해야 합니다. 예를 들어 뷰에 기본 getBackgroundColor()setBackgroundColor() 메서드가 있으므로 backgroundColor가 지원됩니다.
  • 입력해야 하는 다른 속성은 값 유형을 기반으로 합니다. 지원되는 다음 유형 중에서 선택합니다.
    • motion:customColorValue - 색상
    • motion:customIntegerValue - 정수
    • motion:customFloatValue - 부동수
    • motion:customStringValue - 문자열
    • motion:customDimension - 측정기준
    • motion:customBoolean - 부울

맞춤 속성을 지정할 때는 시작 및 끝 <ConstraintSet> 요소 모두에서 엔드포인트 값을 정의합니다.

배경 색상 변경

이전 예를 기반으로 그림 2와 같이 뷰의 모션에 따라 뷰의 색상을 변경하려고 한다고 가정해 보겠습니다.

그림 2. 뷰가 이동하면 배경색이 변경됩니다.

다음 코드 스니펫과 같이 각 ConstraintSet 요소에 <CustomAttribute> 요소를 추가합니다.

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60" />
    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintEnd_toEndOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF" />
    </Constraint>
</ConstraintSet>

추가 MotionLayout 속성

앞의 예시의 속성 외에도 MotionLayout에는 지정할 수 있는 다른 속성이 있습니다.

  • app:applyMotionScene="boolean"는 모션 장면을 적용할지 여부를 나타냅니다. 이 속성의 기본값은 true입니다.
  • app:showPaths="boolean"는 모션이 실행될 때 모션 경로를 표시할지 여부를 나타냅니다. 이 속성의 기본값은 false입니다.
  • app:progress="float"를 사용하면 전환 진행 상황을 명시적으로 지정할 수 있습니다. 0 (전환 시작)부터 1(전환 종료)까지 부동 소수점 값을 사용할 수 있습니다.
  • app:currentState="reference"를 사용하면 특정 ConstraintSet를 지정할 수 있습니다.
  • app:motionDebug를 사용하면 모션에 관한 추가 디버그 정보를 표시할 수 있습니다. 가능한 값은 "SHOW_PROGRESS", "SHOW_PATH" 또는 "SHOW_ALL"입니다.

추가 리소스

MotionLayout에 관한 자세한 내용은 다음 리소스를 참고하세요.