MotionLayout

thsamajiki·2022년 11월 10일
0

UI/UX

목록 보기
3/4
post-thumbnail

MotionLayout이란?

ConstraintLayout 2.0이 출시되면서 MotionLayout이라는 새로운 레이아웃이 등장했다. MotionLayout은 ConstrainLayout을 상속한 레이아웃으로 새로운 방식으로 동적인 화면을 구성한다.

기존에는 애니메이션을 구현하기 위해서는 다음과 같은 기술들을 적용했다.

  • AnimatedVectorDrawable( 모핑 애니메이션 버튼 만들기 )
  • Property Animation
  • LayoutTransition, (Animate layout changes using a transition)
  • CoordinatorLayout(디자인 서포트 라이브러리)

MotionLayout은 기존의 방식과는 다르게 레이아웃 2개를 만든 뒤, 두 레이아웃 사이의 전환효과를 정의한다. 기본적으로 애니메이션되는 프레임들을 탐색 가능하며, 화면 터치 조작과 키프레임 및 각종 화면 전환 효과 등을 지원한다.

MotionLayout은 별도의 Java/Kotlin 코드 작성 없이도 애니메이션을 만들어 낼수 있다. 원하는 애니메이션 효과를 xml만 선언해주면 된다. 현재는 공개되지 않았지만 추후에는 아래와 같은 툴도 쓸 수 있게 될 것입니다.

제약사항

API Level 18 이상 지원 (전체 안드로이드 사용자의 95.9%)
TransitionManager와는 달리, MotionLayout은 중첩된 레이아웃 계층뿐만 아니라 Activity Transition에서도 작동할 수 있는 직접적인 자식뷰에 대한 기능들도 제공한다.


언제 쓰면 좋을까?

MotionLayout은 UI를 움직이거나 사이즈를 조절하고 싶을때 쓸 수 있다. 버튼, 이미지, 타이틀 영역 등 사용자의 조작과 직접적으로 상호작용 할 때 유용하다. 아래의 샘플프로젝트를 다운받아 테스트 해보기 바란다.

샘플 : https://github.com/googlesamples/android-ConstraintLayoutExamples


프로젝트에 MotionLayout 적용해보기

app 모듈 레벨의 gradle에 다음과 같이 추가한다.

dependencies {
    implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha2'
}



MotionLayout의 작동 원리

MotionLayout의 가장 큰 특징이자 장점은 애니메이션에 관련 내용을 별도의 xml로 분리(모듈화,재사용)하여 사용한다는 점이다.

MotionLayout은 ConstraintLayout을 사용할때처럼 화면에 표현하고 싶은 View들과 MotionHelper만을 포함한다. (MotionHelper는 샘플 프로젝트의 21번 FadeIn 참조)

독립된 MotionScene으로 부터 화면 터치에 대한 정의, 키프레임에 대한 정의, 뷰 속성에 대한 정의등을 선언할 수 있으며 MotionLayout은 app:layoutDescription이라는 속성에 MotionScene에 대한 아이디만을 참조하여 사용하게 된다.


MotionLayout의 각 파츠가 어떤 역할을 하는지 하나씩 알아보도록 하자.

<MotionLayout>

MotionScene에서 정의된 ConstraintSet에 의해 레이아웃 간 화면 전환을 지원한다.
그러므로 MotionScene 파일 연결이 필수적으로 필요하며, 연결시에는 “layoutDescription”에 리소스 아이디로 연결한다.

<MotionScene>

MotionScene은 ConstraintSet, 키프레임, 터치 조작, 화면 전환 효과 등의 애니메이션 정보를 포함한 xml 파일이며, res / xml 폴더에 저장되어야 한다.

<Transition>

MotionScene 내에서 정의되며, 화면을 어떤 식으로 전환시킬지에 대한 정의를 한다.

  • constraintSetStart : 첫번째 프레임이 될 제약조건을 정의한 레이아웃 또는 ConstraintSet의 아이디를 참조한다.
  • constraintSetEnd : 마지막 프레임이 될 제약조건을 정의한 레이아웃 또는 ConstraintSet의 아이디를 참조한다.
  • interpolator : 주어진 시간 내에서 어떤 식으로 애니메이션 속도를 조절할건지 정의한다. (예 : easeInOut, linear)
  • duration : 화면전환 애니메이션을 수행하는 시간에 대한 길이를 정의한다.
  • staggered : 0부터 1까지 float 값이 들어가며, duration 내에서 staggered의 값의 비율만큼 애니메이션을 지연시켰다가 빠르게 남은 프레임들의 애니메이션을 실행시킨다. 예를들어 duration의 값이 5이고 staggered의 값은 0.2라고 가정하면 1초정도 애니메이션을 지연시켰다가 4초만에 모든 프레임을 실행시킨다.

<OnSwipe>

Transition 내에서 정의된다. 손끝의 움직임과 화면 전환을 일치시켜주는 핸들러이다. 몇가지 설정해야하는 속성들이 있다.

  • touchAnchorId : 추적하고 싶은 오브젝트 아이디
  • touchAnchorSide : 추적하고 싶은 오브젝트의 측면 쪽 정의. right, left, top, bottom 중 택1
  • dragDirection : 추적하고 싶은 모션의 방향 정의. dragRight, dragLeft, dragUp, dragDown으로 정의할 수 있다. MotionLayout의 progress가 0부터 1까지 어떻게 변화 할 것인지에 대한 정의이다.
  • maxVelocity : touch up 될 때, 애니메이션의 최대 속력값 정의
  • maxAcceleration : touch up 될 때, 얼마나 빨리 애니메이션이 가속하고 감속하는지에 대한 정의
  • moveWhenScrollAtTop : true 또는 false 대입. RecyclerView나 NestedScrollView같은 스크롤 가능한 뷰가 스크롤될 때 애니메이션을 실행시킬지에 대한 정의이다.

<OnClick>

targetView를 클릭했을때 어떤 화면전환 애니메이션 효과를 보여줄지 정의한다.

  • target : 화면전환을 트리거할 뷰 아이디
  • mode : 애니메이션을 실행하는 방법에 대한 정의이다.
  • transitionToEnd : 현재 프레임에서 애니메이션 마지막쪽으로 애니메이션을 실행한다.
  • transitionToStart : 현재 프레임에서 애니메이션의 시작점으로 애니메이션을 실행한다.
  • toggle : 현재 프레임에서 시작점 또는 끝점으로 애니메이션을 토글시키며 애니메이션을 실행한다.
  • jumpToEnd : 애니메이션을 실행시키지 않고 마지막 프레임으로 이동한다.
  • jumpToStart : 애니메이션을 실행시키지 않고 시작ㅈ 프레임으로 이동한다.

<KeyFrameSet>

KeyFrame을 적용하면 자연스럽게 애니메이션에 커브를 적용하거나 모핑을 시도할 수 있다. KeyFrameSet에 적용할 수 있는 태그는 다음과 같다.

  • KeyPosition
  • KeyAttribute
  • KeyCycle

아래의 예제를 확인해보자.

<Transition ...>
    <KeyFrameSet>
        <KeyPosition
            motion:keyPositionType="parentRelative"
            motion:percentY="0.25"
            motion:framePosition="50"
            motion:target="@+id/button"/>
    </KeyFrameSet>
</Transition>

<KeyPosition>

키프레임에서의 뷰의 위치를 지정한다.

  • target : 타겟 뷰의 아이디
  • framePosition : 전체 애니메이션의 프레임을 100이라고 가정할 때 키프레임이 될 프레임의 위치이다. 0 ~ 100 입력
  • transitionEasing : 애니메이션이 실행될때 완만한 곡선을 그리기 위한 값을 정의한다.
  • percentX, percentY : pathRelative내에서 X축 또는 Y축을 따라 비율적으로 거리를 나타낸다.
  • curveFit : 직선을 기반으로 하는 경로(linear) 또는 단조로운 스플라인 곡선을 기반으로 하는 경로를 선택한다.(spline)
  • drawPath : 디버깅을 위해 경로가 나타난다.
  • sizePercent : 뷰 사이즈를 조절한다.
  • keyPositionType : 선형 경로에 대한 키프레임의 편차를 계산하는 방법을 결정한다.
    • deltaRelative : 시작/ 끝 위치를 계산하며 백분율로 나타낸다.


parentRelative와 마찬가지로 상대적으로 직관적인 좌표계이며 일반적으로는 좋은 결과를 나타낸다. 뷰가 수평 또는 수직 동작으로 시작되거나 끝날때 유용하다.
잠재적인 문제가 하나 있는데, 위젯의 시작 위치와 끝 위치의 차이에 따라 정의되므로 차이가 매우 작거나 0인 경우 영향을 받는 축에서 키 프레임의 위치가 변경되지 않는다. 예를 들어 뷰가 화면의 왼쪽에서 오른쪽으로 이동하면서 동일한 높이에 머무르는 경우 위치 키프레임에 deltaRelative percentY를 사용해봐야 아무런 일이 일어나지 않는다.

  • pathRelative : 시작 상태와 끝 상태 사이의 직선 경로를 기준으로 정의된다. deltaRelative를 좌표계로 사용했을때 생기던 문제점을 해결할 수 있으며, 세로 축에서 이동하지 않는 위젯에서도 pathRelative를 사용하면 위치 키 프레임을 이탈 경로로 설정할 수 있다. -좌표도 지원한다. 끝점이 변경되더라도 일정하게 유지되는 곡선 모양(예 : “S”모양)을 얻을 수 있다.

  • parentRelative : 좌표가 부모 컨테이너 기준으로 표현된다. 키프레임의 위치를 표현하는 매우 직관적인 방법이다. 일반적으로 컨테이너에 상대적이여야 하는 계산을 할 때 이 방법을 이용한다.

이 좌표계는 부모 위치에만 기반을 두고있기 때문에 , 결과적으로 키프레임의 위치가 차선적 위치(시작/끝 위치에 상대적)로 끝나는 상황이 발생할 수 있다.

  • pathMotionArc : 둥근 활모양을 어떻게 그릴지 정의한다. (none, flip, startHorizontal, startVertical)

<KeyAttribute>

KeyFrame 내에서 KeyPosition과 비슷한 역할을 하지만 Position이 아닌 Attribute(속성)에 관여한다.

<KeyFrameSet>
    <KeyAttribute
        android:scaleX="2"
        android:scaleY="2"
        android:rotation="-45"
        motion:framePosition="50"
        motion:target="@id/button" />
</KeyFrameSet>

KeyFrame과 비슷한 속성을 가지고 있음( target, framePosition, curveFit, transitionEasing, transitionPathRotate, drawPath, progress)
View에서 사용하는 attribute를 사용할 수 있음. (visibility, alpha, elevation, rotation, rotationX, rotationY, scaleX, scaleY, translationX, translationY, translationZ)
elevation과 translationZ는 API Level 21 이상에서 사용 가능하다.

<ConstraintSet>

ConstraintSet의 기본적인 개념은 모든 레이아웃 위치에 대해 캡슐화를 하는 것이다. View를 재생성할 필요 없이 View에 대한 위치 및 수치만 바꿀 수 있다.

TransitionManager와 함께 동작하며 MotionLayout의 가장 기초적인 부분이 된다.

여러 개의 를 포함할 수 있다.

<Constraint>

특정 뷰에 위치나 크기에 대한 대한 제약 조건을 정의할 수 있습다.

  • View Attribute + ConstraintLayout Attribute 정의
  • transitionEasing : 이 지점에 애니메이션을 적용할 때 사용할 완만한 곡선 정의
  • transitionPathRotate : float 값을 대입. 오브젝트를 상대적으로 회전
  • drawPath : 애니메이션이 작동될 위치의 path가 나타남.
                  테스트 목적이며 실제 출시될 앱에는 나오지 않는것이 좋다.
  • progress : 해당 뷰의 setProgress(float)를 호출한다.

<CustomAttribute>

<Constraint>에 속하며 뷰에 대한 속성을 변경시킬 수 있다. start되는 constraint에서 정의했다면 end쪽도 정의해야 한다.

  • attributeName : 속성에 대한 이름. Case senstive하다. BackgroundColor라고 적으면 setBackgroundColor 메소드를 찾게 된다.
  • 입력에 대한 값은 다음과 같은 타입으로 정의될 수 있다.
    - customColorValue
    - customIntegerValue
    - customFloatValue
    - customStringValue
    - customDimension
    - customBoolean

Conclusion

아직 Alpha 단계의 라이브러리라 관련 자료가 턱없이 부족하며, 구글 안드로이드 개발자 Nicolas Roard의 포스팅을 참조한 것이 9할이다.MotionLayout으로부터 나오는 산출물들이 Awesome인지라 자꾸자꾸 파보게 된다.

직접 개인 프로젝트에 적용해보고, 이런 저런 테스트해본 결과 아직 애니메이션 관련해서 매끄럽지 않은 부분이 많이 보이지만, 정식버전으로 릴리즈 될때는 많은것들이 수정되고 안정화 될것이라고 생각한다.

profile
안드로이드 개발자

0개의 댓글