최근 회사에서 MotionLayout
을 아주 간~단하게 적용하고 있는데, 나는 비교적 최근에 MotionLayout
을 공부하고 사용했었다.
하지만 동료들은 그렇지 않았고, 일정이 넉넉하지 않은 팀 사정 상 MotionLayout
을 사용하는 것은 오직 나 혼자 뿐이었다.
사용하는 데에 다소 러닝커브가 있다면, 쉽게 사용할 수 있는 방법을 찾아보자
애니메이션을 구현하는 방법은 여러가지이며, 그 중 xml파일을 정의해서 사용하는 방식이 있다.
이 방법에서 정의된 애니메이션은 사용하고자 모든 곳에서 재사용된다.
따라서, MotionLayout
에서도 애니메이션을 이루는 xml인 MotionScene
을 단 1번만 정의하고 각각의 MotionLayout
에서 정의된 Scene
을 참조한다면 모든 MotionLayout
에서 동일한 애니메이션을 얻을 수 있다고 생각했다.
이 방법이 유효할 경우, 한 번 정의된 Scene
에 대해서는 그 뒤엔 매우 쉽게 적용이 가능할 것이다.
2개의 액티비티에서 동일한 구조와 id를 가진 MotionLayout
과 그 자식들을 작성한다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="5"
app:layoutDescription="@xml/activity_main_scene"
tools:context=".MainActivity">
<TextView
android:id="@+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</androidx.constraintlayout.motion.widget.MotionLayout>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="5"
app:layoutDescription="@xml/activity_main_scene">
<TextView
android:id="@+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TEST!!!!!" />
</androidx.constraintlayout.motion.widget.MotionLayout>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
각각의 MotionLayout에서 공동으로 참조할 Scene을 작성한다.
간단하게, 화면을 클릭했을 때 TextView가 화면 상단에서 하단으로 움직이는 애니메이션이다.
activity_main_scene.xml
<?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:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
<OnClick motion:clickAction="toggle"/>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"/>
</ConstraintSet>
</MotionScene>
하나의 Scene
을 두 개의 MotionLayout
이 참조하고 있는 상황에서 빌드하여 애니메이션이 정상 적용되는지 확인한다.
두 곳 모두에서 동일한 애니메이션이 적용되었다!
하지만, 이 방법에는 크게 두 가지 제한이 있다.
Scene
을 공유하는 MotionLayout
의 자식들은 모두 같은 id를 가져야 한다.
위 예시 상황에서 MotionLayout
의 자식으로 있는 TextView
의 경우, 모두 같은 id를 가진다 (@id/test)
이 이유는, 공유하는 Scene
의 ConstraintSet
에 포함된 Constraint
의 id와 MotionLayout
의 자식의 id는 같아야 하기 때문이다.
Scene
을 공유하는 MotionLayout
은 같은 구조로 자식을 가져야 한다.
1번과 같은 이유에서, 동일한 애니메이션을 적용하기 위해서는 Scene
의 ConstraintSet
에 포함된 Constraint
의 id와 MotionLayout
의 자식의 id는 같아야 한다.
ex) Scene
의 Constraint
id가 header, body라면 MotionLayout
은 header와 body만을 가진다.
→ 하지만, header와 body는 각각 어떤 자식을 가지는지는 상관이 없다.
한 레이아웃 파일에서 단 1개의 MotionLayout
만이 Scene
을 공유할 수 있다.
2번과 마찬가지로 1번에서 이어지는 내용으로, 한 레이아웃에서 동일한 id를 사용할 수 없기 때문에 Scene
과 같은 id를 가진 MotionLayout
은 한 레이아웃 파일당 단 1개만 존재할 수 있다.
이미 작성된 Scene이 있고, 위 3가지 제한을 어기지 않았다면 아주 간단하게 애니메이션을 적용할 수 있다.
app:layoutDescription
을 이미 작성된 Scene을 참조하도록 한다.이 방법이 틀린 방법일 수 있고, 위에 적어놓은 3가지의 제한이 있지만 그래도 꽤 괜찮은 방법이라고 생각된다.
추후에 저 3가지 제한을 초월하는 방법이 떠오르면 추가로 작성해보도록…….해보겠다.