封装Android带Lottie动画的底部导航栏

Posted ImportSUC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了封装Android带Lottie动画的底部导航栏相关的知识,希望对你有一定的参考价值。

  1. 什么是Lottie动画
    Lottie 是Airbnb开源的一个面向 iosandroid、React Native 的动画库,能分析 Adobe After Effects 导出的动画,并且能让原生 App 像使用静态素材一样使用这些动画,完美实现动画效果,动画效果比原生动画要优美很多。Lottie动画由UI提供,UI给到我们的是xxx.json文件,这个文件就是动画文件。
    优点:动画效果好,灵活,导入方便,使用简单,可以从网络下载,支持多平台。
    缺点:性能没有属性动画好。

  2. 导入Lottie动画库
    github地址
    在app build.gradle 中导入
    implementation 'com.airbnb.android:lottie:$lottieVersion'
    $lottieVersion 为版本号。
    注意2.8.0及之后的版本加入了android x, 如果你的项目没有使用android x ,要使用2.8.0之前的版本,否则会编译失败

Lottie 2.8.0 and above only supports projects that have been migrated
to androidx.

  1. 导入动画文件
    在 main文件夹下创建assets文件夹,将json文件放入assets文件夹下。需要确认json中是否包含本地文件路径,例如 img0/image1.png,如果存在,需要将本地图片按路径存储,否则运行会报错。
  2. 代码中实现动画播放
    关键类 LottieAnimationView ,LottieDrawable 。此类实现Lottie动画的配置及控制。
    LottieAnimationView继承AppCompatImageView,所以它是支持Lottie的Imageview。
mLottieView.setImageAssetsFolder("image0"); //设置本地文件路径
mLottieView.setRepeatCount(0); //设置重复次数,默认0
mLottieView.setAnimation(mAnimationPath);//mAnimationPath 是动画json文件的相对路径
mLottieView.playAnimation();//播放动画  
//其他属性自行搜索

以上配置也可以在xml中配置。

app:lottie_fileName="xxx.json"
app:lottie_repeatCount="0"
app:lottie_imageAssetsFolder="image0"//其他属性自行搜索
  1. 导航栏实现
    新建自定义控件 LottieTabView
public class LottieTabView extends FrameLayout 
    private int mTextNormalColor;
    private int mTextSelectColor;
    private float mTextSize;
    private String mTabName;
    private Drawable mIconNormal;
    private String mAnimationPath;
    private LottieAnimationView mLottieView;
    private TextView mTabNameView;
    private TextView mMsgView;
    private boolean isSelected;

    public LottieTabView(Context context) 
        super(context);
    

    public LottieTabView(Context context, AttributeSet attrs) 
        super(context, attrs);
        init(context, attrs);
    

    public LottieTabView(Context context, AttributeSet attrs, int defStyleAttr) 
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    


    private void init(Context context, AttributeSet attrs) 
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LottieTabView);
        mTextNormalColor = ta.getColor(R.styleable.LottieTabView_text_normal_color, Color.BLACK);
        mTextSelectColor = ta.getColor(R.styleable.LottieTabView_text_selected_color, Color.BLUE);
        mTextSize = ta.getDimension(R.styleable.LottieTabView_text_size, SizeUtils.dp2px(5));
        mIconNormal = ta.getDrawable(R.styleable.LottieTabView_icon_normal);
        mAnimationPath = ta.getString(R.styleable.LottieTabView_lottie_path);
        mTabName = ta.getString(R.styleable.LottieTabView_tab_name);
        isSelected = ta.getBoolean(R.styleable.LottieTabView_tab_selected, false);
        ta.recycle();
        initView(context);
    

    private void initView(Context context) 
        View containView = LayoutInflater.from(context).inflate(R.layout.lottie_tab_view, null, false);
        mLottieView = containView.findViewById(R.id.animation_view);
        mLottieView.setRepeatCount(0);
        mTabNameView = containView.findViewById(R.id.tab_name);
        mTabNameView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
        mTabNameView.setTextColor(mTextNormalColor);
        mTabNameView.setText(mTabName);
        mMsgView = containView.findViewById(R.id.msg_view);
        this.addView(containView);
        if (isSelected) 
            selected();
         else 
            unSelected();
        
    

    public void selected() 
        if (TextUtils.isEmpty(mAnimationPath)) 
            throw new NullPointerException("ainmation path must be not empty");
         else 
            mLottieView.setAnimation(mAnimationPath);
            mLottieView.playAnimation();
            mTabNameView.setTextColor(mTextSelectColor);
        
    

    public void unSelected() 
        mTabNameView.setTextColor(mTextNormalColor);
        mLottieView.clearAnimation();
        mLottieView.setImageDrawable(mIconNormal);
    
	//在右上角显示消息提示数量
    public void showMsg(int num) 
        if (num > 0 && num <= 99) 
            mMsgView.setVisibility(VISIBLE);
            mMsgView.setText(num + "");
         else if (num > 99) 
            mMsgView.setVisibility(VISIBLE);
            mMsgView.setText("99+");
         else 
            mMsgView.setVisibility(View.GONE);
        
    

控件布局文件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:clipToPadding="false"
    android:clipChildren="false">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical">

        <com.airbnb.lottie.LottieAnimationView
            android:id="@+id/animation_view"
            android:layout_width="21dp"
            android:layout_height="23dp" />

        <TextView
            android:id="@+id/tab_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="首页"
            android:textSize="9sp"
            android:textColor="@color/colorMain" />
    </LinearLayout>

        <TextView
            android:id="@+id/msg_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginLeft="10dp"
            android:layout_marginBottom="30dp"
            android:background="@drawable/rc_unread_count_bg"
            android:gravity="center"
            android:textColor="@color/white"
            android:textSize="8sp"
            android:visibility="gone" />

</FrameLayout>

attr.xml中

 <declare-styleable name="LottieTabView">
        <attr name="text_selected_color" format="color"/>
        <attr name="text_normal_color" format="color"/>
        <attr name="text_size" format="dimension"/>
        <attr name="lottie_path" format="string"/>
        <attr name="icon_normal" format="reference"></attr>
        <attr name="tab_selected" format="boolean"></attr>
        <attr name="tab_name" format="string"/>
    </declare-styleable>

界面中使用

        <com.xxx.xxxx.view.widget.LottieTabView
            android:id="@+id/tab_view_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:icon_normal="@drawable/ic_main_normal"
            app:lottie_path="mainpage.json"
            app:tab_name="首页"
            app:tab_selected="true"
            app:text_normal_color="@color/color66"
            app:text_selected_color="@color/colorMain"
            app:text_size="9sp" />

        <com.xxx.xxxx.view.widget.LottieTabView
            android:id="@+id/tab_view_msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:icon_normal="@drawable/ic_msg_normal"
            app:lottie_path="news.json"
            app:tab_name="消息"
            app:tab_selected="false"
            app:text_normal_color="@color/color66"
            app:text_selected_color="@color/colorMain"
            app:text_size="9sp" />

        <com..xxx.xxxx.view.widget.LottieTabView
            android:id="@+id/tab_view_deal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:icon_normal="@drawable/ic_deal_normal"
            app:lottie_path="trade.json"
            app:tab_name="交易"
            app:tab_selected="false"
            app:text_normal_color="@color/color66"
            app:text_selected_color="@color/colorMain"
            app:text_size="9sp" />

        <com.xxx.xxxx.view.widget.LottieTabView
            android:id="@+id/tab_view_mine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:icon_normal="@drawable/ic_mine_normal"
            app:lottie_path="user.json"
            app:tab_name="我的"
            app:tab_selected="false"
            app:text_normal_color="@color/color66"
            app:text_selected_color="@color/colorMain"
            app:text_size="9sp" />
    </LinearLayout>

Mainactivity中

@OnClick(R.id.tab_view_main, R.id.tab_view_msg, R.id.tab_view_deal, R.id.tab_view_mine)
    public void onClickView(View view) 
        switch (view.getId()) 
            case R.id.tab_view_main:
                displayFragment(0);//展示相应的fragment
                mLottieMainTab.selected();
                mLottieMsgTab.unSelected();
                mLottieDealTab.unSelected();
                mLottieMineTab.unSelected();
                break;
            case R.id.tab_view_msg:
                displayFragment(1);
                mLottieMsgTab.selected();
                mLottieDealTab.unSelected();
                mLottieMineTab.unSelected();
                mLottieMainTab.unSelected();
                break;
            case R.id.tab_view_deal:
                displayFragment(2);
                mLottieDealTab.selected();
                mLottieMsgTab.unSelected();
                mLottieMineTab.unSelected();
                mLottieMainTab.unSelected();
                break;
            case R.id.tab_view_mine:
                displayFragment(3);
                mLottieMineTab.selected();
                mLottieMsgTab.unSelected();
                mLottieDealTab.unSelected();
                mLottieMainTab.unSelected();
                break;
        
    

待优化:在此基础上再封装一层LottieTabLayout,动态设置每个LottieTabView的属性。在MainActivity 中直接使用LottieTabLayout。

  1. 效果

    视频录制有些卡顿,现实没有问题。
    所需资源
    demo git

End

以上是关于封装Android带Lottie动画的底部导航栏的主要内容,如果未能解决你的问题,请参考以下文章

如何在小程序导航栏放一个搜索框?

lottie动画实战(仿汽车之家底部Tab切换动画)

Android Compose 新闻App导航动画WebView浮动按钮底部导航

Android Compose 新闻App导航动画WebView浮动按钮底部导航

如何在android中删除底部导航视图的图标动画

Lottie- 让Android动画实现更简单