안드로이드

[Android/Kotlin] MotionLayout - 3 ( Lottie와 ViewPager 활용 )

mingmaeng 2020. 12. 21. 21:16

[이전 포스팅]

[Android / Kotlin] MotionLayout - 1 ( 애니메이션을 쉽게 적용하기 )

[Android / Kotlin] MotionLayout - 2 ( 실제로 적용해보자. )

 

오랜 공백을 깨고 돌아왔습니다. ㅎㅎ

학교도 드디어 종강을 맞이했겠다. 다시 천천히 블로그 포스팅을 진행해보려고 합니다.

그 복귀의 첫 번째 포스팅으로 MotionLayout-2에서 언급했던 실습에 대해서 포스팅하려고 합니다.

( 약 3개월 만의 MotionLayout 시리즈 포스팅.. 가슴이 웅장해진다. )

 


 

이전 포스팅에서 언급했던 대로 이번에는 로티와 뷰 페이저를 연동하여 다음 웹툰의 메인 화면 애니메이션을 연출해보는 ( 비슷하게라도 따라 해 봅시다! ) 시간을 가져보려고 합니다.

 

결과 화면 먼저 보시죠.

 

 

결과 화면을 보시면 뷰 페이저의 전환에 따라서 로티 애니메이션의 진행 상태가 결정됩니다.

다음 웹툰 어플 메인 화면의 모습과 비슷한 느낌을 받죠?

 

좌측 상단의 삼각형 모양이 변한답니다 :)

다음 웹툰에서는 벡터 드로어블의 전환 작업을 일일이 작업했다...라는 소문을 들었습니다만

저희는 좀 더 쉬운 방법을 사용해보겠습니다. 해당 포스팅은 안드로이드 공식문서의 있는 MotionLayout 예제를 참고하여 작성했습니다.

 

안드로이드 공식 개발문서 MotionLayout 예제

Git 문서

 

ViewPager - Lottie 연동 실습

먼저 화면 상단에 Lottie 이미지, 그리고 그 아래에 탭 레이아웃과 뷰 페이저로 구성하도록 하겠습니다.

실습에 사용하실 로티 이미지는 무료로 배포해주는 사이트가 있으니 아래 사이트에서 취향껏 다운로드하시면 됩니다.


[로티 애니메이션 다운로드 사이트 Lottie Files]

lottiefiles.com/

 

LottieFiles - Free animation files built for Lottie

LottieFiles is a collection of animations designed for Lottie - gone are the days of bugging your developer

lottiefiles.com

layout.xml

<?xml version="1.0" encoding="utf-8"?>
<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/motion_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/activity_main2_scene">

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/sample_lottie"
        android:layout_width="0dp"
        android:layout_height="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:lottie_fileName="sampleLottie.json" />

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/sample_tab"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/sample_lottie" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/sample_viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/sample_tab" />


</androidx.constraintlayout.motion.widget.MotionLayout>

 

그다음 해당 레이아웃과 연동된 MotionScene을 설정해줍니다.

 

xml/activity_main2_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">

       <KeyFrameSet>
           <KeyAttribute
               motion:motionTarget="@+id/sample_lottie"
               motion:framePosition="0"
               motion:motionProgress="0"/>
       </KeyFrameSet>

        <KeyFrameSet>
            <KeyAttribute
                motion:motionTarget="@+id/sample_lottie"
                motion:framePosition="100"
                motion:motionProgress="1"/>
        </KeyFrameSet>
    </Transition>

    <ConstraintSet android:id="@+id/start">
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
    </ConstraintSet>
</MotionScene>

 

생각보다 많이 간단합니다. <KeyFrameSet> 태그를 통해서 맨 처음 그리고 맨 마지막 장면에서 각각 Lottie 애니메이션의 진행상황을 0과 1로 설정해주면 됩니다.

그 외의 클릭이나 스와이플 Toggle, <ConstraintSet> 설정은 안 해주셔도 됩니다.

 

메인 코드도 크게 어려움은 없습니다. 뷰페이저를 똑같이 세팅해주시고, addOnPageChageListener를 호출하여 작성해주시면 됩니다.

 

Activity.kt

 

class MainActivity2 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        
        ...
        
        sample_viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
                val progress = (position + positionOffset) / (3 - 1)
                motion_layout.progress = progress
            }

            override fun onPageScrollStateChanged(state: Int) {
            }

            override fun onPageSelected(position: Int) {
            }
        })

        ...
    }
}

뷰페이저에서 스크롤이 감지될 경우 onPageScrolled()가 호출됩니다.

해당 함수 영역 내에서 progress 진행 정도를 계산하여 MotionLayout의 진행도를 변경시켜주면 부드럽게 동작하는 모습을 보실 수 있게 됩니다.

진행도 변경 공식에서 ( 3 - 1 ) 부분은 뷰 페이저의 페이지 개수가 N개일 경우 ( N - 1 )로 설정해주시면 됩니다.


오랜만의 포스팅이라 짧은 내용의 포스팅을 가지고 왔습니다.

저도 다시 제가 작성한 코드들을 보면서 고쳐야 할 점이 굉장히 많다고 느끼네요 ㅎㅎ ( 실습 전체 코드가 3개월 전에 작성한 거였으니... )

 

전체 코드에 대한 Git을 올려놓겠습니다. 궁금하신 분들은 들어가셔서 MainActivity2 부분을 보시면 됩니다!

github.com/kangmin1012/NewAndroidExercise/tree/MotionLayout

 

kangmin1012/NewAndroidExercise

Contribute to kangmin1012/NewAndroidExercise development by creating an account on GitHub.

github.com