天天看點

Lottie動畫學習(Kotlin)

最近一直在學習kotlin,又接觸到 Lottie 動畫,網上是Java寫的 Lottie動畫,我用kotlin寫了一邊,發現了一寫問題。總結一下

Lottie學習文章

Lottie for Android GitHub

Lottie,簡單的說,流程就是(Android為例):UI設計給出動畫的 Json 檔案,放到項目中,加載,展示動畫。

特别說明一下:Lottie 2.8.0,對應的最小SDK,一定要 大于等于16(Android 4.1)。現在很少有低于4.1了吧,注意下就好

我網上找了個動畫對應的Json

出自文章:Lottie開源動畫庫介紹與使用示例

現在,開始使用:

這裡,我先講一下Java的使用,很簡單:

1、我項目中,是用的 androidx

implementation "com.airbnb.android:lottie:2.8.0"
           

2、res檔案夾下,建立raw檔案夾,然後,建立一個:hello_world.json 檔案

(上面提到的,學習文章中,有這麼一句:建議使用 res/raw,因為可以對動畫通過 R 檔案使用靜态引用,而不隻是使用字元串名稱)

3、把上面提到的,動畫對應的 json,複制到 hello_world.json 檔案中

4、布局檔案:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.airbnb.lottie.LottieAnimationView
        android:background="#55ff0000"
        android:id="@+id/animation_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        app:lottie_loop="true"
        app:lottie_rawRes="@raw/hello_world" />

</RelativeLayout>
           

5、代碼中使用:

private boolean animationStatus = false;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_2);

        final LottieAnimationView animationView = findViewById(R.id.animation_view);

        animationView.playAnimation();

        animationView.addAnimatorListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                animationStatus = true;
                Log.e("getAnimatedValue()", "onAnimationStart==" + animationView.isAnimating());
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                animationStatus = false;
                Log.e("getAnimatedValue()", "onAnimationEnd==" + animationView.isAnimating());
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                animationStatus = false;
                Log.e("getAnimatedValue()", "onAnimationCancel==" + animationView.isAnimating());
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                animationStatus = true;
                Log.e("getAnimatedValue()", "onAnimationRepeat==" + animationView.isAnimating());
            }
        });

        //animationView.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        //  @Override
        //  public void onAnimationUpdate(ValueAnimator animation) {
        //      Log.e("getAnimatedValue()",animation.getAnimatedValue()+"");
        //  }
        //});

        animationView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (animationStatus) {
                    animationView.cancelAnimation();
                } else {
                    animationView.playAnimation();
                }
            }
        });
    }
           

到這裡,使用就結束了。很簡單。

接下來,用kotlin實作一下。

建立kotlin項目,然後引入依賴

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'com.android.support:recyclerview-v7:28.0.0'

    implementation "com.airbnb.android:lottie:2.8.0"
}
           

這裡,注意一下:建立後,預設的是:com.android.support

然後,和上面一樣了,差別在于Activity中的使用寫法:

<com.airbnb.lottie.LottieAnimationView
            android:background="#55ff0000"
            android:id="@+id/animation_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            app:lottie_loop="true"
            app:lottie_rawRes="@raw/hello_world" />
           

注意,id 是 animation_view

//動畫狀态,預設是false:不運動
    var animationStatus: Boolean = false

    override fun initView() {
        setContentView(R.layout.activity_main_5)

        animation_view.playAnimation()

        animation_view.addAnimatorListener(object : Animator.AnimatorListener {
            override fun onAnimationRepeat(animation: Animator?) {
                animationStatus = true
                Utils.logE("addAnimatorListener == onAnimationRepeat == " + animation_view.isAnimating)
            }

            override fun onAnimationEnd(animation: Animator?) {
                animationStatus = false
                Utils.logE("addAnimatorListener == onAnimationEnd == " + animation_view.isAnimating)
            }

            override fun onAnimationCancel(animation: Animator?) {
                animationStatus = false
                Utils.logE("addAnimatorListener == onAnimationCancel == " + animation_view.isAnimating)
            }

            override fun onAnimationStart(animation: Animator?) {
                animationStatus = true
                Utils.logE("addAnimatorListener == onAnimationStart ==" + animation_view.isAnimating)
            }
        })

        animation_view.setOnClickListener(object : View.OnClickListener {
            override fun onClick(v: View?) {

                if (animationStatus) {
                    animation_view.cancelAnimation()
                } else {
                    animation_view.playAnimation()
                }
            }
        })
    }
           

然後,運作,就會報錯了:

* What went wrong:
Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : Attribute [email protected] value=(android.support.v4.app.CoreComponentFactory) from [com.android.support:support-compat:28.0.0] AndroidManifest.xml:22:18-91
  	is also present at [androidx.core:core:1.0.0] AndroidManifest.xml:22:18-86 value=(androidx.core.app.CoreComponentFactory).
  	Suggestion: add 'tools:replace="android:appComponentFactory"' to <application> element at AndroidManifest.xml:5:5-31:19 to override.

出了什麼問題:
任務':app:processDebugManifest'執行失敗。
清單合并失敗:屬性[email protected] value=(android. android.support:support-compat:28.0.0) from [com.android.support: compat:28.0.0] AndroidManifest.xml:22:18-91
也存在于[androidx.core:core:1.0.0] AndroidManifest。xml: 22:18 - 86值= (androidx.core.app.CoreComponentFactory)。
建議:在AndroidManifest的 element中添加'tools:replace="android:appComponentFactory"'。xml: 5:5-31:19覆寫。
           

我試過所謂的清單檔案中的加屬性,沒用。

出現這個問題,是因為 androidx 和 android.support 沖突了!

即:androidx 和 項目中預設的 android.support,沖突了!

但是,我們沒有寫 androidx 啊,它在哪裡有使用或者出現呢?

去看下Lottie的源碼下的 build.gradle

裡面明确有一句:

implementation "androidx.appcompat:appcompat:${androidXVersion}"
           

解決辦法:

1、共存。讓 androidx 和 android.support 共存。這樣比較麻煩,代價也大

2、

Lottie動畫學習(Kotlin)

處理之後:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'

    implementation 'androidx.room:room-runtime:2.0.0-beta01'
    annotationProcessor 'androidx.room:room-compiler:2.0.0-beta01'

    implementation "com.airbnb.android:lottie:2.8.0"

}
           

最後,特别說明一下:

我在xml的布局檔案中,指定了,動畫是無限循環的。

那麼,對應的動畫狀态是:

start -> 執行 -> 一次執行完 -> repeat -> 執行 -> ...
           

當執行方法

cancelAnimation()
           

後,狀态是 cancel,但是,這個時候,

@Override
public void onAnimationCancel(Animator animation) {
	Log.e("getAnimatedValue()", "onAnimationCancel==" + animationView.isAnimating());
}
日志:true
           

源碼中執行方法順序我沒找到,不過,看屬性動畫的源碼,是cancel,在end之前執行的,這裡,應該也是。end,對應的 animationView.isAnimating() -> false

如果,動畫隻執行一次,狀态是:

start -> 執行 -> end 

@Override
public void onAnimationEnd(Animator animation) {
	Log.e("getAnimatedValue()", "onAnimationEnd==" + animationView.isAnimating());
}
日志:false