티스토리 뷰

반응형
SMALL

이번 포스트에서는 Lottie 사용법에 대해 간단하게 알아보려고 합니다.

그동안 우리가 만들어온 어플리케이션들이 뭔가 밋밋하고 생동감 넘치지 않은 느낌이 들었던 경험이 한 번쯤은 가지고 있을 것입니다.

그러한 밋밋함을 채워줄 무언가를 소개해드리려고 합니다. AirBnB에서 개발한 Lottie Animation 라이브러리 입니다.

Lottie란?

After Effect에서 제작한 Motion Graphic을 Android에서 그대로 보여줄 수 있는 것으로써 OOM(OUT OF MEMORY)에 대해서도 신경을 많이 쓴 라이브러리 입니다. 이전에 Facebook에서 KeyFrame이라는 라이브러리를 개발했었는데 이보다 더 많은 기능을 제공하는 라이브러리가 바로 Lottie가 되겠습니다. Lottie는 실제 After Effect에서 사용하는 다양한 효과들을 대부분 지원합니다. 따라서 더욱 많은 기능을 구현할 수 있겠습니다. 우리는 이 많은 기능들 중에서 애니메이션 분할하는 방법과 로딩 화면을 위한 애니메이션 사용법에 대해 살펴보도록 하겠습니다.

 

개발 사전 설정

본격 개발을 함에 있어서 우선 우리는 Data Binding을 사용하도록 하겠습니다.

DataBinding에 대해서는 같은 카테고리 내에 간단하게 정리해 놓은 포스트가 있으니 읽어보시면 좋을 것 같습니다.

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.0"
    ...
    dataBinding {
        enabled = true
    }
    ...
}

Gradle파일을 수정하는 부분입니다. dataBinding에 enabled true설정을 해주시면 되겠습니다.

그리고 lottie 라이브러리를 불러오도록 하겠습니다.

dependencies {
	...
    implementation 'com.airbnb.android:lottie:3.0.7'
    ...
}

최신 라이브러리 버전은 Lottie GitHub Page에서 직접 확인하실 수 있습니다. (19. 07. 31. 기준 최신 버전은 3.0.7 입니다.)

json파일은 구글에 검색하시면 sample json 파일 구하실 수 있습니다. (저작권 상 제가 직접 링크를 드릴 수는 없습니다.)

 

json파일은 assets 폴더 안에 넣으시면 되는데 이 폴더를 생성하는 방법은 아래처럼 하시면 됩니다.

app에서 우클릭 - New - Folder - Assets Folder 클릭. 

생성된 assets 폴더에 json 파일을 넣어주시면 됩니다. 파일 명은 영문자 혹은 '_'로 구현되어야 합니다. 이름에서 오류가 나는 경우가 생각보다 많이 있어서 주의해주시면 됩니다. 저는 'animation.json', 'ducks_animation.json'이라고 이름 지었습니다.

레이아웃 설정

<?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>
        <variable
            name="activity"
            type="dev.terrylabs.lottiepractice.MainActivity" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:orientation="vertical">

            <com.airbnb.lottie.LottieAnimationView
                android:id="@+id/lottie_animation_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="#FFffffff"
                android:onClick="@{activity::onClickSwitch}"
                app:lottie_autoPlay="false"
                app:lottie_fileName="animation.json"
                app:lottie_loop="false" />

            <com.airbnb.lottie.LottieAnimationView
                android:id="@+id/lottie_animation_view_duck"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:layout_marginTop="10dp"
                android:layout_weight="1"
                android:background="#FFccefcc"
                android:padding="0dp"
                app:lottie_autoPlay="true"
                app:lottie_fileName="ducks_animation.json"
                app:lottie_loop="true" />
        </LinearLayout>

    </RelativeLayout>
</layout>

레이아웃입니다. Data Binding을 사용하기 때문에 위와 같이 레이아웃을 구성했습니다.

두 가지 애니메이션을 만들 것이기 때문에 LottieAnimationView를 2개 추가하였습니다.

json파일을 LottieAnimationView에 지정하는 방법은 2가지가 있습니다.

1) 레이아웃 파일에서 app:lottie_fileName 옵션에서 직접 지정하는 방법

2) 클래스에서 직접 구현해주는 방법 (바로 아래에서 설명합니다.)

 

애니메이션 구현

이제 애니메이션을 구현해보도록 하겠습니다. 아래 코드를 살펴봐주세요.

public class MainActivity extends AppCompatActivity {

    private boolean isOn = true; // Initial Switch Value is ON
    private ActivityMainBinding binding;
    private final int entireFrame = 106;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setActivity(this);

        binding.lottieAnimationView    .setAnimation("animation.json");
        binding.lottieAnimationViewDuck.setAnimation("ducks_animation.json");
        binding.lottieAnimationViewDuck.setRepeatCount(LottieDrawable.INFINITE);
        binding.lottieAnimationViewDuck.playAnimation();
        //binding.lottieAnimationView.loop(true); // Deprecated
    }

    public void onClickSwitch(View view) {
        this. isOn       = !isOn;
        int   startFrame = isOn ? 50 : 0;
        int   endFrame   = isOn ? 70 : 30;
        float startPoint = (float) startFrame / entireFrame;

        binding.lottieAnimationView.setMaxFrame(endFrame);
        binding.lottieAnimationView.playAnimation();
        binding.lottieAnimationView.setProgress(startPoint);
    }
}

애니메이션은 프레임으로 구성되어 있습니다. 애니메이션의 길이에 따라(시간) 프레임의 수는 달라질 수 있습니다.

 

단순 반복 애니메이션 구현

우선 애니메이션 반복 재생을 살펴보도록 하겠습니다.

binding.lottieAnimationView.setAnimation("animation.json");

위에서 애니메이션 json 파일을 프로그래밍적으로 지정할 수 있다고 했는데 위와 같이 지정할 수 있습니다.

setAnimation 메소드를 통해 json파일을 직접 지정할 수 있고 경로는 Lottie가 알아서 지정해주니 이름만 잘 입력해주시면 됩니다.

binding.lottieAnimationViewDuck.setRepeatCount(LottieDrawable.INFINITE);
binding.lottieAnimationView.loop(true); // Deprecated

위 코드를 보면 loop 메소드와 setRepeatCount메소드가 있습니다. 역할은 동일합니다.

예전에는 loop() 메소드를 사용했는데 메모리 이슈로 인해 Deprecated되었으니 사용하지 말아야 겠습니다.

대신 setRepeatCount 메소드를 사용할 수 있습니다. 인자 값으로 LottieDrawable.INFINITE 를 넣어주게 되면 무한으로 반복 재생할 수 있게 됩니다.

 

애니메이션 분할하기

public void onClickSwitch(View view) {
    this. isOn       = !isOn;
    int   startFrame = isOn ? 50 : 0;
    int   endFrame   = isOn ? 70 : 30;
    float startPoint = (float) startFrame / entireFrame;

    binding.lottieAnimationView.setMaxFrame(endFrame);
    binding.lottieAnimationView.playAnimation();
    binding.lottieAnimationView.setProgress(startPoint);
}

저는 스위치를 애니메이션 형태로 만들어보고 싶었습니다.

Lottie Sample json 파일 중에 스위치 애니메이션 파일이 있었는데 json파일을 보면 On -> Off -> On의 애니메이션이 하나의 json 파일에 들어있습니다. On->Off, Off->On이 별도로 있는 것이 아니었습니다.

그래서 이를 분리할 수 있도록 하고 싶었습니다. 방법은 생각보다 어렵지 않습니다. 간단합니다. 위 코드를 잘 보시기 바랍니다.

 

일단 스위치의 켜짐 여부를 isOn으로 정의하고 있습니다. 필드의 선언은 class 바로 아래에 선언해놓았으니 위로 올라가서 전체 코드를 살펴보시면 될 것 같습니다.

 

아까 애니메이션은 Frame으로 구성된다고 이야기 했었습니다. 제가 사용한 스위치 애니메이션은 106Frames으로 구성된 애니메이션 이었습니다. 따라서 이 프레임 값 조정을 통해 애니메이션 재생 범위를 조정할 수 있을 것이라고 생각했습니다.

binding.lottieAnimationView.setMinFrame(startFrame);
binding.lottieAnimationView.setMaxFrame(endFrame);
binding.lottieAnimationView.playAnimation();

그래서 위와 같은 코드로 하면 되겠지 하고 돌려봤는데 Max 값이 Min 값 보다 작을 수는 없다고 Exception이 발생했습니다.

그래서 반복적인 터치 이벤트로 setMinFrame()과 setMaxFrame()이 호출될 텐데 Exception을 피하기는 힘들겠다고 생각했습니다.

그래서 방법을 조금 변경했습니다. 

Lottie에는 setProgress()라는 메소드가 존재했습니다!

setProgress()를 통해 Start 지점으로 frame을 이동시키고 MaxFrame까지 재생하면 되겠다고 생각했습니다. (완전 천재급)

아래 코드처럼 말이죠.

float startPoint = (float) startFrame / entireFrame;

binding.lottieAnimationView.setMaxFrame(endFrame);
binding.lottieAnimationView.setProgress(startPoint);
binding.lottieAnimationView.playAnimation();

자, 그런데 인생은 호락호락하지 않습니다.(?)

실행을 해보았는데 Switch를 켜도 꺼도 항상 처음부터 재생이 되는 것입니다. 응?? 뭐지..??

계속 생각하다가 아, 떠올랐습니다..(진짜 천재인가...)

playAnimation() 메소드의 위치가 잘못되었다는 것을요...

먼저 플레이를 해주고 위치를 옮겨 주어야 하는데 위치를 옮겨 주고 플레이를 하니까 처음부터 다시 돌아가는 것이었습니다.

그래서 최종적으로 코드를 아래처럼 되었습니다.

float startPoint = (float) startFrame / entireFrame;

binding.lottieAnimationView.setMaxFrame(endFrame);
binding.lottieAnimationView.playAnimation();
binding.lottieAnimationView.setProgress(startPoint);

아, startPoint가 무엇인지 설명을 안했군요.

startPoint는 Progress를 설정해야하는데 이는 0.0f ~ 1.0f 으로 이루어져 있습니다.

그래서 비율을 구하기 위해 [시작 프레임] / [전체 프레임] 을 한 후에 float으로 캐스팅하였습니다.

 

자 이제 애니메이션 구현은 끝이 났습니다. 마지막으로 구현 영상을 보면서 마무리 하겠습니다.

심심하면 광고 하나 재미삼아 눌러보세요~ 나쁜 광고는 없습니다 :)

 

Lottie 애니메이션 실행 화면

 

반응형
LIST
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함