Android 動畫 介紹與使用

KevenZheng發表於2019-05-10

讀前思考

學習一門技術或者看一篇文章最好的方式就是帶著問題去學習,這樣才能在過程中有茅塞頓開、燈火闌珊的感覺,記憶也會更深刻。

  1. Android中有哪幾種型別的動畫?
  2. 幀動畫在使用時需要注意什麼?
  3. View動畫和屬性動畫的區別?
  4. View動畫為何不能真正改變View的位置?而屬性動畫為何可以?
  5. 屬性動畫插值器和估值器的作用?

概述

在 Android 開發中,動畫是必不可少的,它可以讓 View 在變化的時候有一個過渡,避免使用者感覺很突兀。因此,學好動畫,用好動畫是非常重要的,會給開發帶來很多快樂。

Android 中動畫分為幀動畫、View 動畫、屬性動畫三種,可以在日常開發中根據需求的不同進行選擇,但基本上現在 90% 以上的都可以用屬性動畫解決,現在讓我們來了解一下三種動畫。

幀動畫

逐幀動畫是一種常見的動畫形式(Frame By Frame),其原理是在“連續的關鍵幀”中分解動畫動作,也就是在時間軸的每幀上逐幀繪製不同的內容,使其連續播放而成動畫。 因為逐幀動畫的幀序列內容不一樣,不但給製作增加了負擔而且最終輸出的檔案量也很大,但它的優勢也很明顯:逐幀動畫具有非常大的靈活性,幾乎可以表現任何想表現的內容,而它類似與電影的播放模式,很適合於表演細膩的動畫。

在 Android 中提供了兩種方式為 AnimationDrawable 新增幀:XML 定義的資原始檔和 Java 程式碼建立。下面我們會逐一進行介紹。

1. 使用 XML 定義的資原始檔設定動畫幀

 Android 中的資原始檔放在 /res 目錄下,對於動畫幀的資源需要當成一個 Drawable,所以需要把它放在 /res/Drawable 目錄下。而定義逐幀動畫非常簡單,在 drawable 資料夾下新建 xml 檔案,在 <animation-list.../> 元素中使用 <item.../> 子元素定義動畫的全部幀,並制定各幀的持續時間即可。還可以在 <animation-list.../> 元素中新增屬性,來設定逐幀動畫的屬性。

先上效果圖

Android 動畫 介紹與使用

XML幀動畫的資原始檔:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<!-- 定義一個動畫幀,Drawable為img0,持續時間50毫秒 -->
<item android:drawable="@drawable/uncheck_in1" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in2" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in3" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in4" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in5" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in6" android:duration="200"/>
</animation-list>
複製程式碼

Java 程式碼使用動畫

// 通過逐幀動畫的資原始檔獲得AnimationDrawable示例
AnimationDrawable frameAnim = (AnimationDrawable) getResources().getDrawable(R.drawable.part5_frame1);
// 把AnimationDrawable設定為ImageView的背景
mImageView.setBackgroundDrawable(frameAnim);

/**
*根據點選事件控制動畫開啟,停止
*/
@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.bt_start:
            frameAnim.start();
            break;
        case R.id.bt_stop:
            frameAnim.stop();
            break;
    }
}
複製程式碼

2. 使用 Java 程式碼建立逐幀動畫

在 Android 中,除了可以通過 XML 檔案定義一個逐幀動畫之外,還可以通過 AnimationDrawable.addFrame() 方法為 AnimationDrawable 新增動畫幀。
效果圖和上面的一樣,這裡就不放了,直接上程式碼。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_part5_frame_java);

    mImageView = findViewById(R.id.iv_frame1);
    Button bt_stop = findViewById(R.id.bt_stop);
    Button bt_start = findViewById(R.id.bt_start);
    bt_start.setOnClickListener(this);
    bt_stop.setOnClickListener(this);

    frameAnim = new AnimationDrawable();
    // 為AnimationDrawable新增動畫幀
    frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in1), 200);
    frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in2), 200);
    frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in3), 200);
    frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in4), 200);
    frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in5), 200);
    frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in6), 200);
    frameAnim.setOneShot(false);

    mImageView.setBackground(frameAnim);

}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.bt_start:
            if (frameAnim != null && !frameAnim.isRunning()) {
                frameAnim.start();
            }
            break;
        case R.id.bt_stop:
            if (frameAnim != null && frameAnim.isRunning()) {
                frameAnim.stop();
            }
            break;
    }

}
複製程式碼

使用幀動畫的時候要注意不要使用過大的圖片,會引起 OOM。

View 動畫

View 動畫框架只能用於 Views。 比較容易設定和能滿足許多應用程式的需要。View 動畫框架中一共提供了 AlphaAnimation(透明度動畫)、RotateAnimation(旋轉動畫)、ScaleAnimation(縮放動畫)、TranslateAnimation(平移動畫)四種型別的補間動畫;並且 View 動畫框架還提供了動畫集合類(AnimationSet),通過動畫集合類(AnimationSet)可以將多個補間動畫以組合的形式顯示出來。View 動畫只是顯示效果,View 的實際屬性及位置並未發生變化。

先看效果圖

Android 動畫 介紹與使用

在 /res 目錄下新建 anim 資料夾,在 anim 資料夾下新建 xml 檔案

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 透明度變化,從 1 到 0-->
    <alpha
        android:duration="5000"
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
    />
    <!-- 縮放,寬高都是從 1 到 0
         pivotX、pivotY 代表縮放中心點的橫豎座標
         interpolator 代表動畫模式,我設定為先加速、後減速-->
    <scale
        android:duration="5000"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0.0"
        android:toYScale="0.0"
    />
    <!-- 平移動畫,從左上角到右下角-->
    <translate
        android:duration="5000"
        android:fromXDelta="150"
        android:fromYDelta="150"
        android:toXDelta="200"
        android:toYDelta="200"/>
    <!-- 旋轉動畫,fromDegrees 初始角度
          結束角度 toDegrees-->
    <rotate
        android:duration="5000"
        android:fromDegrees="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="+360"/>
</set>
複製程式碼

在程式碼中給 view 新增動畫

ImageView iv_bee=findViewById(R.id.iv_bee);
// 設定動畫資源
Animation loadAnimation =AnimationUtils.loadAnimation(this,R.anim.part5view_anim1);
//動畫結束後保持最後的狀態
loadAnimation.setFillAfter(true);
//給 view 新增動畫
iv_bee.startAnimation(loadAnimation);
複製程式碼

屬性動畫

與屬性動畫相比 View 動畫存在一個缺陷,View 動畫改變的只是 View 的顯示,而沒有改變View的響應區域,並且 View 動畫只能對 View 做四種型別的補間動畫,因此在 Android3.0 及其後續版本中新增了屬性動畫框架。

屬性動畫理論知識有很多講解,可以具體看下面的文章

HenCoder Android 自定義 View 1-6:屬性動畫 Property Animation(上手篇)

Android屬性動畫深入分析:讓你成為動畫牛人

我這裡就不講理論了,直接擼效果

1、 數字滾動效果

Android 動畫 介紹與使用

很簡單的一個數字滾動效果,用屬性動畫也很容易做出來,幾行程式碼搞定

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_part5_object_anim);

    mTv_object = findViewById(R.id.tv_object);
    Button bt_start=findViewById(R.id.bt_start);
    bt_start.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showMoneyAnim(1,500);
        }
    });
}

private void showMoneyAnim(int mStartValue, int mEndValue) {
    ValueAnimator animator = ValueAnimator.ofInt(mStartValue, mEndValue);
    animator.setDuration(3000);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mTv_object.setText(animation.getAnimatedValue().toString());
            }
        });
    animator.start();

    }
複製程式碼
2、 簽到卡片翻轉效果

Android 動畫 介紹與使用

具體翻轉程式碼,分為上半段和下半段動畫

public class Part4AnimationActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_part4_animation);


        final ImageView iv_animation=findViewById(R.id.iv_animation);
        iv_animation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                applyRotation(false,iv_animation,0,-90);
            }
        });
    }

    /**
     * 設定一個新的三維旋轉的容器檢視。只翻一般,然後設定新的現實內容
     *
     * @param zheng
     *            一個判斷機制 如果為true 則向右翻轉,如果false則向左翻轉
     * @param view
     *            傳入的片段
     * @param start
     *            起始位置
     * @param end
     *            結束位置
     */
public void applyRotation(final boolean zheng, final View view,
        final float start, final float end) {
        // Find the center of the container
        final float centerX = view.getWidth() / 2.0f;
        final float centerY = view.getHeight() / 2.0f;

        // Create a new 3D rotation with the supplied parameter
        // The animation listener is used to trigger the next animation
        final Util_Rotate3DAnimation rotation = new Util_Rotate3DAnimation(
                start, end, centerX, centerY, 310.0f, true);
        rotation.setDuration(500);
        rotation.setFillAfter(true);
        rotation.setInterpolator(new AccelerateInterpolator());
        rotation.setAnimationListener(new DisplayNextView(zheng, view));// 新增監聽執行現實內容的切換
        view.startAnimation(rotation);// 執行上半場翻轉動畫
    }

    /**
     * 執行完上半部分旋轉之後,設定要顯示的新的View然後繼續執行下半部分旋轉
     */
private final class DisplayNextView implements Animation.AnimationListener {
        private final boolean mPosition;
        private final View mView;

        private DisplayNextView(boolean zheng, View view) {
            mPosition = zheng;
            mView = view;
        }

        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {
            mView.post(new SwapViews(mPosition, mView));// 新增新的View
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }
    /**
     * 新增要顯示的新的View,並執行下半部分的旋轉操作
     */
private final class SwapViews implements Runnable {
        private final boolean mPosition;
        private final ImageView mView;

        public SwapViews(boolean position, View view) {
            mPosition = position;
            mView = (ImageView) view;
        }

        public void run() {
            final float centerX = mView.getWidth() / 2.0f;
            final float centerY = mView.getHeight() / 2.0f;
            Util_Rotate3DAnimation rotation;

            if (mPosition) {
                rotation = new Util_Rotate3DAnimation(-90, 0, centerX, centerY,
                        310.0f, false);
            } else {
                rotation = new Util_Rotate3DAnimation(90, 0, centerX, centerY,
                        310.0f, false);
            }
            mView.setImageResource(R.drawable.head2);

            rotation.setDuration(500);
            rotation.setFillAfter(true);
            rotation.setInterpolator(new DecelerateInterpolator());
            mView.startAnimation(rotation);
        }
    }

}
複製程式碼

文章已經讀到末尾了,不知道最初的幾個問題你都會了嗎?如果不會的話?可以再針對不會的問題進行精讀哦!答案都在文中,相信你肯定可以解決的!

相關文章