Lottie - 動(dòng)畫的使用

一、前言:

Lottie 是Airbnb開源的一個(gè)面向 iOS、Android、React Native 的動(dòng)畫庫,能分析 Adobe After Effects 導(dǎo)出的動(dòng)畫,并且能讓原生 App 像使用靜態(tài)素材一樣使用這些動(dòng)畫,完美實(shí)現(xiàn)動(dòng)畫效果。

現(xiàn)在使用各平臺的 native 代碼實(shí)現(xiàn)一套復(fù)雜的動(dòng)畫是一件很困難并且耗時(shí)的事,我們需要為不同尺寸的屏幕加載不同的素材資源,還需要寫大量難維護(hù)的代碼,而Lottie可以做到同一個(gè)動(dòng)畫文件在不同平臺上實(shí)現(xiàn)相同的效果,極大減少開發(fā)時(shí)間,實(shí)現(xiàn)不同的動(dòng)畫,只需要設(shè)置不同的動(dòng)畫文件即可,極大減少開發(fā)和維護(hù)成本。

Lottie 地址:https://github.com/airbnb/lottie-android

Lottie 官網(wǎng):https://airbnb.design/lottie/

1、為什么使用Lottie?

  1. 跨平臺只有制作一套json動(dòng)畫文件便可以跨平臺在 Android ios ReactNeative上使用,lottie庫負(fù)責(zé)解析json文件并播放動(dòng)畫

  2. 可以支持網(wǎng)絡(luò)下載json文件,本地播放,實(shí)時(shí)更新動(dòng)畫資源。

  3. 運(yùn)行時(shí)效率上僅僅用Canvas去draw而已,流暢度非常棒,所以哪怕在Listview里去大量顯示,內(nèi)存占用和繪圖效率都遠(yuǎn)遠(yuǎn)高于幀動(dòng)畫。

  4. 實(shí)現(xiàn)效果可以按設(shè)計(jì)出的100%還原到產(chǎn)品中。

  5. 開發(fā)周期大大減少。

二、使用:

1、在項(xiàng)目 的 build.gradle 文件添加依賴

dependencies {
     //lottie框架(現(xiàn)在的最新版本)
    implementation'com.airbnb.android:lottie:3.4.1'
}

注意:版本過老,會(huì)報(bào)錯(cuò)

2、 添加 Adobe After Effects 導(dǎo)出的動(dòng)畫文件

Lottie默認(rèn)讀取Assets中的文件,我們需要把設(shè)計(jì)導(dǎo)出的動(dòng)畫文件.json 保存在app/src/main/assets文件里。

位置.png

比如p_start.json中包含本地圖片,則在assets中新建images文件夾,將圖片放入即可


圖片.png

3、 使用Lottie

  1. 直接布局加載*.json文件的方法:
  <com.airbnb.lottie.LottieAnimationView
            android:id="@+id/animation_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            app:lottie_fileName="app_loading.json"
            app:lottie_loop="true" />

lottie_fileName表示本地Assets文件中存的json動(dòng)畫文件

lottie_loop表示動(dòng)畫循環(huán)執(zhí)行

2、代碼加載動(dòng)畫方法

<com.airbnb.lottie.LottieAnimationView
            android:id="@+id/animation_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:lottie_fileName="app_loading.json"
            app:lottie_loop="true"
            app:lottie_autoPlay="true" />

lottie_autoPlay表示設(shè)置是否自動(dòng)啟動(dòng)播放

        //聲明控件
        lottieAnimationView = findViewById(R.id.animation_view);
        //這個(gè)可有可無,如果不涉及本地圖片做動(dòng)畫可忽略
       // lottieAnimationView.setImageAssetsFolder("images");
        //設(shè)置動(dòng)畫文件
        lottieAnimationView.setAnimation("app_loading.json");
        //是否循環(huán)執(zhí)行
        lottieAnimationView.loop(true);
        //執(zhí)行動(dòng)畫
        lottieAnimationView.playAnimation();

  1. 加載網(wǎng)絡(luò).json文件
private void loadUrl(String url) {
        Request request = new Request.Builder().url(url).build();
        OkHttpClient client = new OkHttpClient();
        client.newCall(request).enqueue(new Callback() {
            @Override public void onFailure(Call call, IOException e) {}
            @Override public void onResponse(Call call, Response response) throws IOException {
                try {
                    JSONObject json = new JSONObject(response.body().string());
                    LottieComposition.Factory
                            .fromJson(getResources(), json, new OnCompositionLoadedListener() {
                                @Override
                                public void onCompositionLoaded(LottieComposition composition) {
                                    lottieAnimationView.setComposition(composition);
                                    lottieAnimationView.playAnimation();
                                }
                            });
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }

  1. 使用包含本地圖片的lottie動(dòng)畫
    XML使用:
   <com.airbnb.lottie.LottieAnimationView
                android:id="@+id/lottie_view"
                android:layout_width="@dimen/dp_70"
                android:layout_height="@dimen/dp_50"
                app:lottie_fileName="p_start.json"
                app:lottie_imageAssetsFolder="images/"
                android:layout_below="@+id/tv_level1"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="@dimen/dp_6"
                />

java代碼:

   //動(dòng)畫1
    private fun initAnible() {
        //這個(gè)可有可無,如果不涉及本地圖片做動(dòng)畫可忽略
        lottie_view.setImageAssetsFolder("images/");
        //設(shè)置動(dòng)畫文件
        lottie_view.setAnimation("p_start.json");
        //是否循環(huán)執(zhí)行
        //lottie_view.loop(true);
        lottie_view.setOnClickListener {
            //執(zhí)行動(dòng)畫
            lottie_view.playAnimation()
        }
    }

三、 常用方法

  • 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
  • 監(jiān)聽動(dòng)畫進(jìn)度
  • 設(shè)置動(dòng)畫硬件加速
  • 緩存動(dòng)畫
  • Lottie本身在 Android 平臺已經(jīng)做了適配工作,而且適配原理很簡單,解析時(shí),從 讀取寬高之后會(huì)再乘以手機(jī)的密度。再在使用的時(shí)候判斷適配后的寬高是否超過屏幕的寬高,如果超過則再進(jìn)行縮放。以此保障 Lottie 在 Android 平臺的顯示效果

四、自定義刷新頭

public class CustomClassicsHeader extends LinearLayout implements RefreshHeader {

    private TextView mHeaderText;//標(biāo)題文本
//    private ImageView mArrowView;//下拉箭頭
//    private ImageView mProgressView;//刷新動(dòng)畫視圖
//    private ProgressDrawable mProgressDrawable;//刷新動(dòng)畫
    private LottieAnimationView lottieAnimationView;//加載動(dòng)畫
    private   View view;
    public CustomClassicsHeader(Context context) {
        this(context, null);
    }

    public CustomClassicsHeader(Context context, AttributeSet attrs) {
        super(context, attrs, 0);

         view = LayoutInflater.from(context).inflate(R.layout.item_custom_header, this);
//        setGravity(Gravity.CENTER);
//        mHeaderText = new TextView(context);
//        mProgressDrawable = new ProgressDrawable();
////        mArrowView = new ImageView(context);
////        mProgressView = new ImageView(context);
//        lottieAnimationView = new LottieAnimationView(context);
//        //mProgressView.setImageDrawable(mProgressDrawable);
//        //mArrowView.setImageDrawable(new ArrowDrawable());
//
//        mHeaderText.setTextColor(context.getResources().getColor(R.color.color_FF333333));
////        addView(mProgressView, SmartUtil.dp2px(20), SmartUtil.dp2px(20));
////        addView(mArrowView, SmartUtil.dp2px(20), SmartUtil.dp2px(20));
//        addView(lottieAnimationView, SmartUtil.dp2px(25), SmartUtil.dp2px(25));
//        addView(new Space(context), SmartUtil.dp2px(20), SmartUtil.dp2px(20));
//        addView(mHeaderText, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
//        setMinimumHeight(SmartUtil.dp2px(60));
//        //加載動(dòng)畫
//        lottieAnimationView.setAnimation("app_pull_refresh.json");
//        //是否循環(huán)執(zhí)行
//        lottieAnimationView.loop(true);


        lottieAnimationView = view.findViewById(R.id.lottieAnimationView);
        mHeaderText = view.findViewById(R.id.tv_head);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @NonNull
    public View getView() {
        return view;//真實(shí)的視圖就是自己,不能返回null
    }

    @NonNull
    @Override
    public SpinnerStyle getSpinnerStyle() {
        return SpinnerStyle.Translate;//指定為平移,不能null
    }

    @Override
    public void onStartAnimator(@NonNull RefreshLayout layout, int height, int maxDragHeight) {
       // mProgressDrawable.start();//開始動(dòng)畫
        //執(zhí)行動(dòng)畫
        lottieAnimationView.playAnimation();
    }

    @Override
    public int onFinish(@NonNull RefreshLayout layout, boolean success) {
//        mProgressDrawable.stop();//停止動(dòng)畫
//        mProgressView.setVisibility(GONE);//隱藏動(dòng)畫
        lottieAnimationView.cancelAnimation();
        if (success) {
            mHeaderText.setText("刷新完成");
        } else {
            mHeaderText.setText("刷新失敗");
        }
        return 500;//延遲500毫秒之后再彈回
    }

    @Override
    public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
        refreshLayout.setPrimaryColorsId(R.color.color_FFF96857,R.color.color_FFF96857);//全局設(shè)置主題顏色
        switch (newState) {
            case None:
            case PullDownToRefresh:
                mHeaderText.setText("下拉開始刷新");
//                mArrowView.setVisibility(VISIBLE);//顯示下拉箭頭
//                mProgressView.setVisibility(GONE);//隱藏動(dòng)畫
//                mArrowView.animate().rotation(0);//還原箭頭方向

                break;
            case Refreshing:
                mHeaderText.setText("正在刷新");
//                mProgressView.setVisibility(VISIBLE);//顯示加載動(dòng)畫
//                mArrowView.setVisibility(GONE);//隱藏箭頭
                break;
            case ReleaseToRefresh:
                mHeaderText.setText("釋放立即刷新");
               // mArrowView.animate().rotation(180);//顯示箭頭改為朝上
                break;
        }
    }

    @Override
    public void setPrimaryColors(int... colors) {

    }

    @Override
    public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) {

    }

    /**
     * 移動(dòng)
     * @param isDragging
     * @param percent
     * @param offset
     * @param height
     * @param maxDragHeight
     */
    @Override
    public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) {
        if(isDragging){
            //設(shè)置進(jìn)度
            lottieAnimationView.setProgress(percent);
        }

    }

    @Override
    public void onReleased(@NonNull RefreshLayout refreshLayout, int height, int maxDragHeight) {

    }

    @Override
    public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {

    }

    @Override
    public boolean isSupportHorizontalDrag() {
        return false;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/dp_70"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:background="@color/color_FFFFFF"
    >
    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottieAnimationView"
        android:layout_width="@dimen/dp_35"
        android:layout_height="@dimen/dp_35"
        android:layout_marginTop="@dimen/dp_10"
        app:lottie_fileName="app_pull_refresh.json"
        app:lottie_loop="true"
        app:lottie_autoPlay="true"
        android:layout_centerHorizontal="true"
        />

    <TextView
        android:id="@+id/tv_head"
        android:layout_marginTop="@dimen/dp_3"
        android:layout_below="@+id/lottieAnimationView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/color_FFA9A9A9"
        android:textSize="@dimen/sp_11"
        android:layout_centerHorizontal="true"
        android:text="下拉開始刷新"
        />
</RelativeLayout>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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