【從 0 開始開發(fā)一款直播 APP】14 animation-list 逐幀動畫自定義 Switch 控件

本文為菜鳥窩作者蔣志碧的連載。“從 0 開始開發(fā)一款直播 APP ”系列來聊聊時下最火的直播 APP,如何完整的實現(xiàn)一個類"騰訊直播"的商業(yè)化項目


一、Android 中的逐幀動畫

先來說說什么是逐幀動畫,逐幀動畫是一種常見的動畫形式(Frame By Frame),其原理是在「連續(xù)的關(guān)鍵幀」中分解動畫動作,也就是在時間軸的每幀上逐幀繪制不同的內(nèi)容,使其連續(xù)播放而成動畫。 因為逐幀動畫的幀序列內(nèi)容不一樣,不但給制作增加了負擔而且最終輸出的文件量也很大,但它的優(yōu)勢也很明顯:逐幀動畫具有非常大的靈活性,幾乎可以表現(xiàn)任何想表現(xiàn)的內(nèi)容,而它類似與電影的播放模式,很適合于表演細膩的動畫。

在 Android 中逐幀動畫需要得到 AnimationDrawable 類的支持,是 Drawable 的間接子類。它主要用來創(chuàng)建一個逐幀動畫,并且可以對幀進行拉伸,把它設(shè)置為 View 的背景即可使用 AnimationDrawable.start() 方法播放。既然逐幀動畫是需要播放一幀一幀的圖像,所以需要為其添加幀。

AnimationDrawable 結(jié)構(gòu)圖

官方示例

用于創(chuàng)建逐幀動畫的對象,由一系列 Drawable 對象定義,可用作 View 對象的背景。 創(chuàng)建逐幀動畫的最簡單的方法是將 XML 文件中的動畫定義在 res/drawablefolder 中,并將其設(shè)置為 View 對象的背景。 然后,調(diào)用start() 來運行動畫。 在 XML 中定義的 AnimationDrawable 由單個 <animation-list> 元素和一系列嵌套的 <item> 標簽組成。 每個項目定義一個動畫框架。 參見下面的例子。


二、利用逐幀動畫實現(xiàn)自定義 Switch 控件

在谷歌的 Material Design 官方專題中,花了整整一頁來介紹 Delightful Details,其中有幀動畫的絕佳例子。


接下來講解直播中用到的控件,效果如下

定義了兩個 Animation-list,文件存放在 res/drawable 目錄下

switch_open.xml

<?xml version="1.0" encoding="utf-8"?>
<!--
    根標簽為animation-list,其中 oneshot 代表著是否只展示一遍,設(shè)置為 false 會不停的循環(huán)播放動畫
    根標簽下,通過 item 標簽對動畫中的每一個圖片進行聲明
    android:duration 表示展示所用的該圖片的時間長度
 -->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/btn_switch_off" android:duration="80"/>
    <item android:drawable="@drawable/btn_switch_press" android:duration="80"/>
    <item android:drawable="@drawable/btn_switch_on" android:duration="80"/>
</animation-list>

switch_close.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="false">
    <item android:drawable="@drawable/btn_switch_on" android:duration="80" />
    <item android:drawable="@drawable/btn_switch_press" android:duration="80" />
    <item android:drawable="@drawable/btn_switch_off" android:duration="80" />
</animation-list>

CustomSwitch.java

CustomSwitch 繼承自 AppCompatImageView,AppCompatImageView 繼承自 ImageView,實現(xiàn)其構(gòu)造函數(shù)和方法

public class CustomSwitch extends android.support.v7.widget.AppCompatImageView {
    private boolean mChecked = false;
    private AnimationDrawable mAnimationDrawable;
    private Handler mHandler;
    private Runnable mRunnable;
    
    //這里三個構(gòu)造函數(shù)參數(shù)類似,相互調(diào)用,在第三個構(gòu)造函數(shù)中初始化動畫
    public CustomSwitch(Context context) {
        this(context, null);
    }
    public CustomSwitch(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    //初始化動畫
    private void init() {
        mHandler = new Handler();
        mRunnable = new Runnable() {
            @Override
            public void run() {
                onAnimation();
            }
        };
    }

    /**
     * 動畫播放
     */
    private void onAnimation() {
        //判斷是否選中
        if (mChecked) {
            setImageResource(R.drawable.btn_switch_on);
        } else {
            setImageResource(R.drawable.btn_switch_off);
        }
    }
    //設(shè)置選中
    public void setChecked(boolean checked, boolean playAnim) {
        if (checked == mChecked) {
            return;
        }
        mChecked = checked;
        //判斷是否正在播放
        if (playAnim) {
            setImageResource(mChecked ? R.drawable.switch_open : R.drawable.switch_close);
            mAnimationDrawable = (AnimationDrawable) getDrawable();
            mAnimationDrawable.start();
            mHandler.postDelayed(mRunnable, getTotalDuration(mAnimationDrawable));
        }
    }

    /**
     * 返回總時長
     * @param animationDrawable
     * @return
     */
    private long getTotalDuration(AnimationDrawable animationDrawable) {
        int duration = 0;
        for (int i = 0; i < animationDrawable.getNumberOfFrames(); i++) {
            duration += animationDrawable.getDuration(i);
        }
        return duration;
    }

    public boolean isChecked() {
        return mChecked;
    }
}

三、CustomSwitch 的使用

activity_publish.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                tools:ignore="contentDescription"> 
    <com.dali.admin.livestreaming.ui.customviews.CustomSwitch
        android:id="@+id/btn_lbs"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:clickable="true"
        android:focusable="true"
        android:gravity="center"
        android:onClick="onClick"
        android:src="@drawable/btn_switch_off"/>
</RelativeLayout>

PublishActivity.java

public class PublishActivity extends BaseActivity implements View.OnClickListener{

    private CustomSwitch mBtnSwitch;

    @Override
    protected void setActionBar() {

    }

    @Override
    protected void setListener() {
        mBtnSwitch.setOnClickListener(this);
    }

    @Override
    protected void initData() {
      
    }

    @Override
    protected void initView() {
        mBtnSwitch = obtainView(R.id.btn_record);
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_publish;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_record:
                if (mBtnSwitch.isChecked()) {
                    mBtnSwitch.setChecked(false, true);
                    mTvRecord.setText("不進行錄制");
                } else {
                    mBtnSwitch.setChecked(true, true);
                    mTvRecord.setText("進行錄制");
                }
                break;
        }
}

詳情請轉(zhuǎn)至 GitHub
參考:

https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

http://www.cnblogs.com/plokmju/p/android_AnimationDrawable.html

擼這個項目的一半,你就是大神 , 戳http://mp.weixin.qq.com/s/ZagocTlDfxZpC2IjUSFhHg

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

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

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