Android MotionLayout(모션 레이아웃) basic1 (feat.codelab)
https://codelabs.developers.google.com/codelabs/motion-layout#0
https://www.youtube.com/watch?v=M1jE3W3_NTQ&list=PLWz5rJ2EKKc_PEOEHNBEyy6tPX1EgtUw2
2018년에 발표되어 UI에 애니메이션을 추가하는 툴이다. 현재 단방향 데이터 흐름에 맞춘 개발트렌드 때문에 compose로 많이들 넘어가거나 리팩토링을 진행하는 추세긴 하지만, 여전히 2024년에도 viewSystem은 많은 곳에서 사용되고 있으며, viewSystem의 ui에 애니메이션을 추가하는 도구로는 유용하기에 간단하게 공식문서와 youtubu를 참고하여 정리하려고 한다.
motionlayout
- ConstraintLayout의 서브 클래스인 MotionLayout
- MotionLayout 태그 내에서 애니메이션으로 표시될 모든 view를 지정
- MotionScene MotionLayout의 애니메이션을 설명하는 XML 파일
- Transtion 애니메이션 지속 시간, 트리거 및 뷰 이동 방법을 지정
- ConstraintSet Transition의 start 및 end, 제약 조건을 모두 지정
모든 애니메이션은 시작과 끝으로 정의할 수 있습니다.
시작은 애니메이션 이전 화면의 모습을 정의하고 끝은 애니메이션이 완료된 후 화면의 모습을 정의합니다.
MotionLayout은 (시간 경과에 따라) 시작 상태와 끝 상태 사이에서 애니메이션을 적용하는 방법을 파악하여 적용한다.
<ConstraintSet> && <Constraint>
MotionScene은 <ConstraintSet> 태그를 사용하여 시작 및 종료 상태를 정의합니다.
ConstraintSet은 말 그대로 뷰에 적용할 수 있는 제약 조건 집합입니다.
width, height 및 ConstraintLayout 제약 조건이 포함됩니다. 또한 alpha(투명도)와 같은 일부 속성도 포함됩니다.
ConstraintSet에 지정된 모든 제약 조건은 레이아웃 파일에 지정된 제약 조건을 재정의합니다.
layout과 MotionScene 모두에 제약 조건을 정의하면 MotionScene의 제약 조건만 적용됩니다.
즉, MotionScene의 제약조건이 우선되어 적용된다.
원본 activity.xml
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/activity_step1_scene">
<ImageView
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="30dp"
android:contentDescription="@string/star"
app:srcCompat="@drawable/ic_star_outline"
app:tint="?colorSecondary" />
</androidx.constraintlayout.motion.widget.MotionLayout>
activity_motion_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>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
</ConstraintSet>
</MotionScene>
ConstraintSet 내부의<Constraint>는 제한을 해야되는 view의 원본 layout id를 id로지정합니다.
<Constraint>는 제약 조건과 레이아웃 정보만 지정한다는 점을 기억하는 것이 중요합니다.
Constraint 태그는 자신이 ImageView에 적용되고 있다것을 모른다.
MotionLayout을 사용할 때 원본 layout 대신 motion Scene XML 파일에서 애니메이션으로 표시되는 모든 뷰의 제약 조건을 지정
애니메이션이 적용되지 않은 뷰는 motion Scene 이 아니라 원본 layout 에서 제약을 지정하면 된다.
<Transition>
Transition은 MotionScene의 하나의 애니메이션을 설명합니다.
애니메이션 중에 변경되는 View, 애니메이션 소요 시간, 애니메이션을 구동하기 위해 사용자 터치를 처리하는 방법을 포함하여 MotionLayout에 대한 전체 애니메이션에 대한 사양이 포함되어 있습니다.
MotionScene에는 하나 이상의 애니메이션/Transition 이 있을 수 있습니다.
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
</Transition>
<OnClick>
애니메이션을 시작하는 방법을 정의하는 태그입니다.
targetId는 정의된 애니메이션을 시작하는 view id입니다.
toggle의 clickAction은 클릭 시 시작 상태와 종료 상태 간에 전환됩니다.
즉, 터치하면 시작상태 -> 종료상태 다시 터치하면 종료상태 -> 시작상태 로 애니메이션이 적용된다.
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
<OnClick motion:targetId="@+id/red_star"
motion:clickAction="toggle"/>
</Transition>
<OnSwipe>
MotionLayout은 View를 이동하기 위한 터치 이벤트를 tracking할 수 있으며, 모션을 유동적으로 만들기 위한 physics-based fling gestures를 지원합니다. 뷰를 Swipe할 경우 view 애니메이션이 계속 진행되고 표면을 가로질러 굴러갈 때 물리적 객체처럼 속도가 느려진다는 것을 의미합니다. <Transition> OnSwipe 태그를 사용하여 추가할 수 있습니다.
OnSwipe에는 몇 가지 속성이 포함되어 있으며 가장 중요한 속성은 touchAnchorId입니다.
- touchAnchorId는 터치에 반응하여 움직임이 Tracking 되는 뷰입니다. MotionLayout은 이 뷰를 스와이프하는 손가락으로부터 동일한 거리를 유지합니다.
- touchAnchorSide는 추적해야 하는 뷰의 측면을 결정합니다.
이는 크기가 조정되거나, 복잡한 경로를 따르거나, 한쪽이 다른 쪽보다 빠르게 움직이는 뷰에 중요합니다.
- dragDirection은 이 애니메이션에 중요한 방향(위, 아래, 왼쪽 또는 오른쪽)을 결정합니다.
MotionLayout이 드래그 이벤트를 수신하면 리스너는 touchAnchorId로 지정된 View가 아닌 MotionLayout에 등록됩니다.
사용자가 화면 어디에서나 동작을 시작하면 MotionLayout은 손가락과 touchAnchorId 보기의 touchAnchorSide 사이의 거리를 일정하게 유지합니다. 예를 들어 앵커 측면에서 100dp 떨어진 곳을 터치하면 MotionLayout은 전체 애니메이션 동안 해당 측면을 손가락에서 100dp 떨어진 곳에 유지합니다.
OnSwipe는 touchAnchorId에 지정된 View가 아닌 MotionLayout의 스와이프를 수신합니다. 이는 사용자가 애니메이션을 실행하기 위해 지정된 View 밖으로 스와이프할 수 있다.