2019-08-03-Android動(dòng)畫總結(jié)

動(dòng)畫分類

1,幀動(dòng)畫

顧名思義,就是連續(xù)播放多張不同的圖片,形成的動(dòng)畫效果,這個(gè)必須是放在Drawable文件夾下,下面是XML的方式

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/loading0" android:duration="120"/>
    <item android:drawable="@color/loading1" android:duration="120"/>
    <item android:drawable="@color/loading2" android:duration="120"/>
</animation-list>

代碼的方式

private AnimationDrawable mAnimationDrawable;
public AnimationDrawable getAnimationDrawableList() {
    if(mAnimationDrawable == null) {
        mAnimationDrawable = new AnimationDrawable();
        for (int i = 0; i < 5; i++) {
            int identifier = getResources().getIdentifier("loading"+i, "drawable", getPackageName());
            mAnimationDrawable.addFrame(getResources().getDrawable(identifier), 120);
        }
    }
    return mAnimationDrawable;
}
2,補(bǔ)間動(dòng)畫

這類動(dòng)畫只需要定義動(dòng)畫的開始和結(jié)束,時(shí)長,不需要定義動(dòng)畫的每一幀,通過對View的內(nèi)容進(jìn)行一系列的圖像變換來實(shí)現(xiàn)的

主要包括四種基本的效果

  • 透明度變化Alpha
  • 大小變化Scale
  • 位移變化 Translate
  • 旋轉(zhuǎn)變化 Retate

提到動(dòng)畫不得不提到插值器Interpolator,負(fù)責(zé)控制動(dòng)畫變化的速度。

通俗的可以理解為物理上的加速度。

同理,它能實(shí)現(xiàn)的基本效果就是勻速,加速,減速,拋物線等多種速度變化

  • Interpolator其實(shí)是一個(gè)接口,繼承自TimeInterpolator
  • public interface Interpolator extends TimeInterpolator {
    }

    public interface TimeInterpolator {
    float getInterpolation(float input);
    }

該接口只有一個(gè)float getInterpolation(float input);方法,入?yún)⑹且粋€(gè)0.0-1.0的值,返回值可以小于0.0,也可以大于1.0

Android已經(jīng)默認(rèn)幫我們實(shí)現(xiàn)了好幾種的插值器,具體看Android
的源碼

補(bǔ)間動(dòng)畫使用比較簡單一些,這里就不放源碼了,大家可以自行閱讀Android
源碼,查看實(shí)現(xiàn)方式

3,屬性動(dòng)畫

屬性動(dòng)畫是Android3.0引入的,補(bǔ)間動(dòng)畫我們只是改變了View的繪制效果,而View的實(shí)際屬性是沒有發(fā)生變化的。而屬性動(dòng)畫正是直接View的屬性來實(shí)現(xiàn)的,同時(shí)屬性動(dòng)畫可以在任何對象上,不僅僅限于View

定義屬性動(dòng)畫需要的一些基本屬性

  • 動(dòng)畫持續(xù)時(shí)間-通過android:duration來指定
  • 動(dòng)畫的插值方式,這個(gè)和補(bǔ)間動(dòng)畫的插值器理解類似通過android:interpolater來指定
  • 動(dòng)畫的重復(fù)次數(shù)-通過android:repeatCount來指定
  • 動(dòng)畫的重復(fù)模式-通過android:repeatMode來指定
  • 幀刷新頻率
  • 動(dòng)畫集合 -實(shí)現(xiàn)多個(gè)屬性動(dòng)畫的組合使用-通過android:ordeing來指定這組動(dòng)畫是按照次序還是同時(shí)播放,資源文件中通過<set></set>來表示

屬性動(dòng)畫中,另外一個(gè)重要的概念就是 Evaluator

Evaluator是用來控制屬性動(dòng)畫是如何來計(jì)算屬性值的-可以理解為每次對象屬性的變化率

public interface TypeEvaluator<T> {
    public T evaluate(float fraction, T startValue, T endValue);
}

常見的實(shí)現(xiàn)類就是IntEvaluator,F(xiàn)loatEvaluator,ArgbEvaluator,我們來看下ArgbEvaluator的實(shí)現(xiàn)方式,實(shí)現(xiàn)的邏輯就是根據(jù)輸入的初始值和結(jié)束值及一個(gè)進(jìn)度比,計(jì)算出每一個(gè)進(jìn)度的ARGB值

public class ArgbEvaluator implements TypeEvaluator {
    private static final ArgbEvaluator sInstance = new ArgbEvaluator();

    public static ArgbEvaluator getInstance() {
        return sInstance;
    }

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        float startA = ((startInt >> 24) & 0xff) / 255.0f;
        float startR = ((startInt >> 16) & 0xff) / 255.0f;
        float startG = ((startInt >>  8) & 0xff) / 255.0f;
        float startB = ( startInt        & 0xff) / 255.0f;

        int endInt = (Integer) endValue;
        float endA = ((endInt >> 24) & 0xff) / 255.0f;
        float endR = ((endInt >> 16) & 0xff) / 255.0f;
        float endG = ((endInt >>  8) & 0xff) / 255.0f;
        float endB = ( endInt        & 0xff) / 255.0f;

        // convert from sRGB to linear
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);

        // compute the interpolated color in linear space
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // convert back to sRGB in the [0..255] range
        a = a * 255.0f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

        return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
    }
}
4,屬性動(dòng)畫-AnimatorSet

AnimatorSet是Animator的子類,它可以指定多個(gè)屬性動(dòng)畫是順序執(zhí)行還是同時(shí)執(zhí)行

5,屬性動(dòng)畫-ValueAnimator實(shí)現(xiàn)

ValueAnimator是屬性動(dòng)畫中最重要的一個(gè)類,它定義了屬性動(dòng)畫大部分的核心功能,包括計(jì)算各個(gè)幀的屬性值,處理更新事件,按照屬性值的類型控制計(jì)算規(guī)則等

一個(gè)完整的屬性動(dòng)畫可以由倆部分組成

  • 計(jì)算動(dòng)畫各個(gè)幀的屬性值
  • 將這些屬性值設(shè)置給指定的對象

ValueAnimator為我們實(shí)現(xiàn)了第一部分的功能,第二部分由我們開發(fā)者自己來實(shí)現(xiàn)。ValueAnimator的構(gòu)造函數(shù)是空實(shí)現(xiàn),一般都是使用靜態(tài)工廠方法來實(shí)現(xiàn)

下面是實(shí)現(xiàn)一個(gè)完整的ValueAnimator的動(dòng)畫流程

1,定義一個(gè)Evaluator

public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

2,定義一個(gè)Interpolator

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;
    }
}

3,開始動(dòng)畫

public void startAnim(Object target, int from, int to, int duration) {
    ValueAnimator va = ValueAnimator.ofInt(from, to);
    va.setInterpolator(new LinearInterpolator());
    va.setEvaluator(new IntEvaluator());
    va.setDuration(duration);
    va.setTarget(this);
    va.addUpdateListener(animator -> {
        int value = (int) animator.getAnimatedValue();//
        animator.getAnimatedFraction();//動(dòng)畫執(zhí)行的百分比0-1
        target.update(value);


    });
    va.start();
}

4,停止動(dòng)畫

public void stopAnim() {
    va.cancel();
}
5,屬性動(dòng)畫-ObjectAnimator實(shí)現(xiàn)

ObjectAnimator動(dòng)畫是ValueAnimator的子類,實(shí)現(xiàn)的上面提到的第二部分功能。它和ValueAnimator最大的不同就是構(gòu)造的時(shí)候需要指定作用的對象和對象的屬性名,而且不需要實(shí)現(xiàn)addUpdateListener接口

public class CustomProgressBar extends ProgressBar {
    public CustomProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setProgressWithAnim(int progress, int duration) {
        ObjectAnimator animator = ObjectAnimator.ofInt(this, "progress", progress);
        animator.setDuration(duration);
        animator.start();
    }
}

使用ObjectAnimator有以下幾點(diǎn)需要注意:

  • 需要為對象對應(yīng)的屬性提高setter方法,例如上面的setProgress方法

  • 如果動(dòng)畫的對象是View,那么為了能讓其顯示動(dòng)畫效果,某些情況下可能還是需要注冊addUpdateListener,在回調(diào)中刷新view的顯示

  • 屬性動(dòng)畫也可以在XML中定義

      <set xmlns:android="http://schemas.android.com/apk/res/android">
      <!--消失-->
      <objectAnimator android:duration="0"
                      android:propertyName="alpha"
                      android:valueFrom="1.0"
                      android:valueTo="0.0"/>
          
      <!--旋轉(zhuǎn)-->
      <objectAnimator android:duration="300"
                      android:propertyName="rotationY"
                      android:valueFrom="360"
                      android:valueTo="0"/>
      </set>
    

獲取XML屬性動(dòng)畫

AnimatorSet as = AnimatorInflater.loadAnimator(context, R.animator.animator);
as.setTarget(mBackView);
as.start();
6,屬性動(dòng)畫-XxxAnimator.ofPropertyValuesHolder使用

先上代碼

 public static ObjectAnimator getPulseAnimator(View labelToAnimate, float decreaseRatio,
        float increaseRatio) {
    Keyframe k0 = Keyframe.ofFloat(0f, 1f);
    Keyframe k1 = Keyframe.ofFloat(0.275f, decreaseRatio);
    Keyframe k2 = Keyframe.ofFloat(0.69f, increaseRatio);
    Keyframe k3 = Keyframe.ofFloat(1f, 1f);

    PropertyValuesHolder scaleX = PropertyValuesHolder.ofKeyframe("scaleX", k0, k1, k2, k3);
    PropertyValuesHolder scaleY = PropertyValuesHolder.ofKeyframe("scaleY", k0, k1, k2, k3);
    ObjectAnimator pulseAnimator =
            ObjectAnimator.ofPropertyValuesHolder(labelToAnimate, scaleX, scaleY);
    pulseAnimator.setDuration(PULSE_ANIMATOR_DURATION);

    return pulseAnimator;
}

PropertyValuesHolder這個(gè)類的意義就是,它其中保存了動(dòng)畫過程中所需要操作的屬性和對應(yīng)的值

Keyframe直譯過來就是關(guān)鍵幀

關(guān)鍵幀這個(gè)概念是從動(dòng)畫里學(xué)來的,類似幀動(dòng)畫,我們指定的每一張圖片就是一個(gè)關(guān)鍵幀
Keyframe就相當(dāng)于定義幀動(dòng)畫中的每一個(gè)圖片顯示的時(shí)間和位置

fraction:表示當(dāng)前的顯示進(jìn)度,即從加速器中g(shù)etInterpolation()函數(shù)的返回值;
value:表示當(dāng)前應(yīng)該在的位置 
public static Keyframe ofFloat(float fraction, float value)
  • 比如Keyframe.ofFloat(0f, 1f);表示動(dòng)畫進(jìn)度為0時(shí),動(dòng)畫所在的數(shù)值位置為0
  • Keyframe.ofFloat(0.275f, decreaseRatio)表示動(dòng)畫進(jìn)度為27.5%時(shí),動(dòng)畫所在的數(shù)值位置為decreaseRatio
  • Keyframe.ofFloat(1f,1f)表示動(dòng)畫結(jié)束時(shí),動(dòng)畫所在的數(shù)值位置為1
?著作權(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ù)。

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

  • 【Android 動(dòng)畫】 動(dòng)畫分類補(bǔ)間動(dòng)畫(Tween動(dòng)畫)幀動(dòng)畫(Frame 動(dòng)畫)屬性動(dòng)畫(Property ...
    Rtia閱讀 6,390評論 1 38
  • 一: 傳統(tǒng) View 動(dòng)畫(Tween/Frame) 1.1 Tween 動(dòng)畫 主要有 4 中:縮放、平移、漸變、...
    dfg_fly閱讀 853評論 1 2
  • 1 背景 不能只分析源碼呀,分析的同時(shí)也要整理歸納基礎(chǔ)知識,剛好有人微博私信讓全面說說Android的動(dòng)畫,所以今...
    未聞椛洺閱讀 2,852評論 0 10
  • Animation Animation類是所有動(dòng)畫(scale、alpha、translate、rotate)的基...
    四月一號閱讀 2,031評論 0 10
  • 動(dòng)畫基礎(chǔ)概念 動(dòng)畫分類 Android 中動(dòng)畫分為兩種,一種是 Tween 動(dòng)畫、還有一種是 Frame 動(dòng)畫。 ...
    Rtia閱讀 1,360評論 0 6

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