Lottie 入門與實(shí)踐

Lottie庫(kù)Airbnb出的是一個(gè)能夠幫助Android,iOS解析AE導(dǎo)出的包含動(dòng)畫信息的json文件。AE實(shí)現(xiàn)這個(gè)是通過(guò)Bodymovin這個(gè)插件,但是這事應(yīng)該是設(shè)計(jì)師去關(guān)心的就不是開發(fā)人員去關(guān)注的了。

美工需要做的可以參考Lottie- 讓Android動(dòng)畫實(shí)現(xiàn)更簡(jiǎn)單

[TOC]

引入庫(kù)

dependencies {
    ...
    compile 'com.airbnb.android:lottie:2.2.0'
    ...
}

使用LottieAnimationView

可以直接在xml中聲明

<com.airbnb.lottie.LottieAnimationView        
android:id="@+id/animation_view"    
android:layout_width="wrap_content"    
android:layout_height="wrap_content"
app:lottie_fileName="hello-world.json"        
app:lottie_loop="true"        
app:lottie_autoPlay="true" 
/>
  • app:lottie_fileName="hello-world.json"指定了顯示的動(dòng)畫文件,該文件放在assert文件夾下,如圖:

    若要在assets的子文件夾下,例如Walthrough下的例如Walthrough.json則為:Walkthrough/Walkthrough.json
  • app:lottie_loop="true"設(shè)置是否循環(huán)播放
  • app:lottie_autoPlay="true"設(shè)置是否自動(dòng)啟動(dòng)播放

讀取Json

獲得加載json動(dòng)畫文件有很多種方式:



(1)最簡(jiǎn)單的就是之前放在asserts文件夾下,直接讀取就好
(2)還能通過(guò)網(wǎng)絡(luò)獲取Json后加載,因?yàn)檎也坏骄W(wǎng)絡(luò)json動(dòng)畫資源沒有測(cè)試,貼一下官方文檔的代碼:

//獲取json數(shù)據(jù)并實(shí)例化JsonObject
 JSONObject json = new JSONObject(response.body().string());
 Cancellable compositionCancellable = LottieComposition.Factory.fromJson(getResources(), json, (composition) -> {
     animationView.setComposition(composition);
     animationView.playAnimation();
 });
 // 通過(guò)cancel來(lái)停止對(duì)于composition的異步加載
 //compositionCancellable.cancel();

動(dòng)態(tài)添加

LottieAnimationView animationView = (LottieAnimationView) findViewById(R.id.animation_view);
animationView.setAnimation("hello-world.json");
animationView.loop(true);
animationView.playAnimation();

具體的方法含義參考xml中聲明的解釋就好。

常用方法

  • animationView.isAnimating();動(dòng)畫是否在播放
  • animationView.playAnimation();播放動(dòng)畫
  • animationView.pauseAnimation();暫停動(dòng)畫
  • animationView.cancelAnimation();取消動(dòng)畫
  • animationView.setProgress(progress); 設(shè)置進(jìn)度,progress范圍0~1
  • animationView.setMinAndMaxProgress(min,max); 設(shè)置播放范圍,0~1,測(cè)試目前有bug,設(shè)置播放時(shí)間后再恢復(fù)播放,進(jìn)度會(huì)跳過(guò)一段時(shí)間

管理動(dòng)畫

繪制監(jiān)聽器

//每次動(dòng)畫繪制會(huì)調(diào)用
animationView.addAnimatorUpdateListener((animation) -> {
    // 可以用來(lái)獲取播放進(jìn)度并同步進(jìn)度條
    float progress = (Float) animation.getAnimatedValue()*100f;
    seekbar.setProgress(((int) progress));
});

自定義播放速度與區(qū)間

//一秒內(nèi)值由0變化為1,可以通過(guò)float值管理動(dòng)畫播放區(qū)間,設(shè)置duration控制播放速度
ValueAnimator animator =ValueAnimator.ofFloat(0f, 1f)
    .setDuration(1000);//1s
animator.addUpdateListener(animation -> {
    //通過(guò)由0->1的變化模擬動(dòng)畫播放
    animationView.setProgress(animation.getAnimatedValue());
});
//最終使用ValueAnimator管理動(dòng)畫播放
animator.start();

實(shí)踐與應(yīng)用

基本動(dòng)畫播放與進(jìn)度管理


這個(gè)實(shí)現(xiàn)沒什么難點(diǎn),就是通過(guò)seekbar監(jiān)聽管理進(jìn)度:

        sbBaseAnimation.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                animationView.setProgress(progress/100f);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                animationView.pauseAnimation();
                btnPlayAnim.setText("播放動(dòng)畫");
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });

實(shí)現(xiàn)圖標(biāo)切換動(dòng)畫


原理也很簡(jiǎn)單,本質(zhì)上是這個(gè)圖標(biāo)是一個(gè)動(dòng)畫,list->back是從前往后播放,而back->list則是從后往前倒著播放。因?yàn)檫@個(gè)json動(dòng)畫過(guò)長(zhǎng),所以只截取其中一段就達(dá)到了效果,這個(gè)應(yīng)用感覺對(duì)業(yè)務(wù)還是比較有用的。

    private static final int TOTAL_DURATION = 2000;
    private static final float START_PROGRESS_PART = 0.1f;
    private static final float END_PROGRESS_PART = 0.3f;
    
 //用于記錄當(dāng)前按鈕狀態(tài)
    boolean isBackState = false;
    
    @OnClick(R.id.anim_button)
    public void onViewClicked() {
        if(animatorComplete!=null&&animatorComplete.isRunning()){
            animatorComplete.cancel();
            animatorComplete = null;
        }
        //以下的參數(shù)是為了實(shí)現(xiàn)在動(dòng)畫播放到一半又需要切換時(shí),能夠直接往回播放的效果
        float progress = animButton.getProgress();
        //這次動(dòng)畫播放需要的時(shí)長(zhǎng),因?yàn)閺闹虚g挽回播時(shí)間也會(huì)變短所以要實(shí)時(shí)計(jì)算
        int nowDuration = 0;
        //這次播放起點(diǎn)與終點(diǎn)的差值
        float nowGap;
        //動(dòng)畫從頭到尾播放的起終點(diǎn)差值
        float totalGap = END_PROGRESS_PART - START_PROGRESS_PART;
        if (isBackState) {
            //back->list
            nowGap = progress - START_PROGRESS_PART;
            nowDuration = (int) ((nowGap* TOTAL_DURATION)/totalGap);
            animatorComplete = ValueAnimator.ofFloat(progress, START_PROGRESS_PART)
                    .setDuration(nowDuration);
        } else {
            //list->back
            nowGap = END_PROGRESS_PART - progress;
            nowDuration = (int) ((nowGap* TOTAL_DURATION)/totalGap);
            animatorComplete = ValueAnimator.ofFloat(progress, END_PROGRESS_PART)
                    .setDuration(nowDuration);
        }
        animatorComplete.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                animButton.setProgress((Float) animation.getAnimatedValue());
                tvProgress.setText("animatorComplete"+animation.getAnimatedValue()+"");
            }
        });
        isBackState = !isBackState;
        animatorComplete.start();
    }

動(dòng)畫中自定義字體與動(dòng)態(tài)文字

代碼實(shí)現(xiàn)很簡(jiǎn)單,就是原理有點(diǎn)弄不清楚:

TextDelegate textDelegate = new TextDelegate(animFont);
animationView.setTextDelegate(textDelegate);
//這里input寫為NAME(原文本)才能更改成其他文字
textDelegate.setText("NAME","動(dòng)態(tài)更改的文本");

其中“NAME”這個(gè)文本是在json動(dòng)畫文本中指定的,動(dòng)態(tài)更改需要在textDelegate.setText()中將原文本設(shè)置為在Json文件中指定的文本才能實(shí)現(xiàn)動(dòng)態(tài)更改。
而文本的字體是在也是在json中指定的,使用時(shí)也需要在asserts/font/文件夾下放入相應(yīng)的.tts字體文件才能保證動(dòng)畫的正常運(yùn)行。
這一類可以實(shí)現(xiàn)更改動(dòng)畫中的字體和文本,代碼參考了官方demo,但是官方文檔目前沒有對(duì)使用到的類進(jìn)行具體說(shuō)明,所以具體原理不好弄清楚,之前關(guān)于“NAME”與字體文件的相關(guān)說(shuō)明也是我查看json文件后猜測(cè)得出的結(jié)論,不一定正確,僅供參考。

引導(dǎo)動(dòng)畫

展示效果是通過(guò)結(jié)合了sliding-intro-screen簡(jiǎn)單的實(shí)現(xiàn)了引導(dǎo)頁(yè)面,然后通過(guò)監(jiān)聽引導(dǎo)頁(yè)面的操作,同步管理動(dòng)畫的進(jìn)度就實(shí)現(xiàn)了。具體Lottie官方的Demo中邏輯也是自己寫的,沒有封裝。也就是說(shuō)如果我們要實(shí)現(xiàn)這種效果的話,還是需要自己進(jìn)行邏輯處理的Lottie并沒有現(xiàn)成的包。

打字動(dòng)畫


打字動(dòng)畫官方是自定義了FrameLayout,代碼太多所以沒細(xì)看,猜測(cè)本質(zhì)上也是一個(gè)個(gè)的動(dòng)畫view,只不過(guò)使用了有利于重用的LottieComposition。

參考文獻(xiàn)

lottie官方文檔
Lottie- 讓Android動(dòng)畫實(shí)現(xiàn)更簡(jiǎn)單

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,094評(píng)論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,401評(píng)論 4 61
  • 引入jquery.js 和jq.lazy.js 圖片加上類 lazy src可以為空,也可以加一個(gè)加載圖片 但一定...
    給我小前端閱讀 279評(píng)論 0 0

友情鏈接更多精彩內(nèi)容