動畫(Property Animation)(閃閃星光示例+知識點)

概述:

Property Animation,屬性動畫非常強(qiáng)大,Android官方API如是說:屬性動畫系統(tǒng)是一個強(qiáng)大的框架,它幾乎可以將動畫添加到任何東西上。它是在View Animation之后引入的,那么相比較有什么優(yōu)勢:
1,Property Animation不僅可以使View收縮,旋轉(zhuǎn)而且可以改變View的color,size等屬性值。而且作用范圍不局限于View,而是任何對象。
2,Property Animation使視圖發(fā)生了改變同時View的真實位置也發(fā)生了改變。
3,更少的代碼做更多的事情。

詳解:

了解Property Animation可以從下面三個方面來了解:

1,Animators

Animator相關(guān)類為我們提供了創(chuàng)建屬性動畫的方法。涉及到的類如下圖所示:


Paste_Image.png

Animator:為我們提供了一些基礎(chǔ)的方法,如添加監(jiān)聽,開始,取消動畫等方法。

ValueAnimator:提供了一個簡單的計時引擎,通過計算動畫值并將它們設(shè)置在目標(biāo)對象上, 用于運行動畫??梢杂么a定義,也可以用xml,個人覺得在代碼中比較常用,這里列舉下在代碼中創(chuàng)建的方法:

ValueAnimator()
static ValueAnimator ofArgb(int... values)
static ValueAnimator ofFloat(float... values)
static ValueAnimator ofInt(int... values)
static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)
static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)

ObjectAnimator: ValueAnimator的這個子類提供了對目標(biāo)對象上的動畫屬性的支持。View對象對應(yīng)的propertyName一般有這幾個:alpha, translationX,translationY,x,y,rotation,rotationX,rotationY,scaleX,scaleY。如果記不住可在View的源碼中查看。

ObjectAnimator()
static ObjectAnimator ofInt(Object target, String propertyName, int... values)
static ObjectAnimator ofArgb(Object target, String propertyName, int... values)
static ObjectAnimator ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)
...

TimeAnimator: 比ValueAnimator多了一個TimeListener,用于監(jiān)聽執(zhí)行總時間以及當(dāng)前幀和上一幀的時差。

//示例     
timeAnim.setTimeListener(new TimeAnimator.TimeListener() {
            @Override
            public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
            }
});

AnimatorSet:可以將多個Animator一起或者按照一定的順序執(zhí)行。

//示例
AnimatorSet anim = new AnimatorSet();
anim.play(rotateAnim).after(transferAnim).with(timeAnim);
anim.start();
2,Evaluators

賦值器告訴屬性動畫系統(tǒng)如何計算給定屬性的值。Android提供了下面這些賦值器。


Paste_Image.png
//這是Android中IntEvaluator實現(xiàn)代碼我們也可以通過繼承TypeEvaluator來實現(xiàn)自己的Evaluator。關(guān)鍵重載
evaluate方法就可以了。
public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

ValueAnimator提供了setEvaluator(TypeEvaluator value)來設(shè)置賦值器。那計算出來的值我們也可以在下面的回調(diào)中通過來getAnimatedValue()獲取。

    transferAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                valueAnimator.getAnimatedValue();
            }
        });
2,Interpolators

時間插值器定義動畫中的具體值如何作為時間的函數(shù)計算。通俗講就是用什么樣的速率(勻速,變速等待)來展示。Android提供了下面這些插值器,基本上見名知意。

Paste_Image.png
//這是Android中AccelerateInterpolator 實現(xiàn)代碼,我們也可以通過繼承Interpolator 來實現(xiàn)自己的Interpolator ,關(guān)鍵重載getInterpolation(float input)方法就可以了。
public class AccelerateInterpolator implements Interpolator {
    private final float mFactor;
    private final double mDoubleFactor;

    public AccelerateInterpolator() {
        mFactor = 1.0f;
        mDoubleFactor = 2.0;
    }

    public AccelerateInterpolator(float factor) {
        mFactor = factor;
        mDoubleFactor = 2 * mFactor;
    }
    
    public AccelerateInterpolator(Context context, AttributeSet attrs) {
        TypedArray a =
            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);
        
        mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
        mDoubleFactor = 2 * mFactor;

        a.recycle();
    }
    
    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }
}

ValueAnimator提供了setInterpolator和getInterpolator方法來設(shè)置插值器。

示例:

通過上面的文字,我們了解了創(chuàng)建屬性動畫的基本類和方法,我們通過示例來進(jìn)一步熟悉用法。
獵豹清理大師通知欄清理界面有一個閃星星的動畫效果,我們實現(xiàn)下后效果如下圖:

ezgif.com-ddf5c08218.gif
實現(xiàn)代碼

首先新建一個ShiningStar.java的類。

public class ShiningStar extends View {

    /**
     * 星星的坐標(biāo)及大小
     */
    private static final int[][] starPosition = new int[][] {
            {80, 80, 66},{160, 80, 80},{240,160, 100},{120, 240, 120},{360, 480, 66}, {600, 600, 120}, {720, 500, 120},
            {360, 100, 66}, {600, 160, 120}, {720, 240, 120},{860, 80, 80}
    };

    /**
     * 星星存儲器
     */
    private List<Star> stars = new ArrayList<Star>();

    /**
     * 星星資源
     */
    private Bitmap bitmap = null;

    /**
     * 畫筆
     */
    private Paint paint = null;

    public ShiningStar(Context context) {
        super(context);
        init();
    }

    public ShiningStar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ShiningStar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap != null) {
            for (int i = 0; i < stars.size(); i++) {
                canvas.save();//這樣使每一個星星的狀態(tài)獨立
                Rect dst = new Rect(stars.get(i).x, stars.get(i).y, stars.get(i).x + stars.get(i).size, stars.get(i).y + stars.get(i).size);
                canvas.scale(stars.get(i).scale,  stars.get(i).scale, stars.get(i).x + stars.get(i).size/2, stars.get(i).y + stars.get(i).size/2);
                paint.setAlpha((int)stars.get(i).alpha);
                canvas.drawBitmap(bitmap, null, dst, paint);
                canvas.restore();
            }
        }
    }

    /**
     * 初始化
     */
    private void init() {
        initStars();
        initAnimation();
    }

    /**
     * 初始化星星對象
     */
    private void initStars() {
        for (int i = 0; i < starPosition.length; i++) {
            final Star star = new Star();
            star.x = starPosition[i][0];
            star.y = starPosition[i][1];
            star.size = starPosition[i][2];
            star.scale = 1;
            star.alpha = 255;
            stars.add(star);
        }
    }

    /**
     * 初始化動畫及繪制元素的對象
     */
    private void initAnimation() {
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.star_icon);
        paint = new Paint();
        paint.setAlpha(255);

        ValueAnimator scaleAnim = ValueAnimator.ofFloat(0, 255, 0);
        scaleAnim.setInterpolator(new LinearInterpolator());
        scaleAnim.setDuration(1000);
        scaleAnim.setRepeatCount(-1);
        scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                boolean flag = false;
                for (int i = 0; i < stars.size(); i++) {
                    if (flag) {
                        stars.get(i).scale = ((float)animation.getAnimatedValue())/255;
                        stars.get(i).alpha = (float)animation.getAnimatedValue();
                    } else {
                        stars.get(i).scale = 1 - ((float)animation.getAnimatedValue())/255;
                        stars.get(i).alpha = 255 - (float)animation.getAnimatedValue();
                    }
                    flag = !flag;
                }
                postInvalidate();
            }
        });
        scaleAnim.start();
    }

    /**
     * 星星屬性
     */
    class Star {
        int x;
        int y;
        int size;
        float scale;
        float alpha;
    }
}

2,新建一個layout文件。

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="#2196F3"
    tools:context="com.wayne.android.viewanimation.MainActivity">

    <com.wayne.android.viewanimation.ShiningStar
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layout_centerHorizontal="true"/>
</RelativeLayout>

3,在Activity中引用

setContentView(R.layout.activity_main);

這個例子中我們用到了ValueAnimator 來實現(xiàn)星星的閃動效果。那我們能否改造一下使用ObjectAnimator呢,當(dāng)然可以。

public class ShiningStar extends View {

    /**
     * 星星的坐標(biāo)及大小
     */
    private static final int[][] starPosition = new int[][] {
            {80, 80, 66},{160, 80, 80},{240,160, 100},{120, 240, 120},{360, 480, 66}, {600, 600, 120}, {720, 500, 120},
            {360, 100, 66}, {600, 160, 120}, {720, 240, 120},{860, 80, 80}
    };

    /**
     * 星星存儲器
     */
    private List<Star> stars = new ArrayList<Star>();

    /**
     * 星星資源
     */
    private Bitmap bitmap = null;

    /**
     * 畫筆
     */
    private Paint paint = null;

    protected  float starScale = 1f;

    protected float starAlpha = 255f;

    public ShiningStar(Context context) {
        super(context);
        init();
    }

    public ShiningStar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ShiningStar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap != null) {
            boolean flag = false;
            for (int i = 0; i < stars.size(); i++) {
                canvas.save();//這樣使每一個星星的狀態(tài)獨立
                Rect dst = new Rect(stars.get(i).x, stars.get(i).y, stars.get(i).x + stars.get(i).size, stars.get(i).y + stars.get(i).size);
                android.util.Log.i("TestShining", "scale: " + starScale);
                if (flag) {
                    canvas.scale(starScale,  starScale, stars.get(i).x + stars.get(i).size/2, stars.get(i).y + stars.get(i).size/2);
                    paint.setAlpha((int)starAlpha);
                } else {
                    canvas.scale(1 - starScale,  1 - starScale, stars.get(i).x + stars.get(i).size/2, stars.get(i).y + stars.get(i).size/2);
                    paint.setAlpha((int)(255 - starAlpha));
                }
                flag = !flag;
                canvas.drawBitmap(bitmap, null, dst, paint);
                canvas.restore();
            }
        }
    }

    /**
     * 初始化
     */
    private void init() {
        initStars();
        initAnimation();
    }

    /**
     * 初始化星星對象
     */
    private void initStars() {
        for (int i = 0; i < starPosition.length; i++) {
            final Star star = new Star();
            star.x = starPosition[i][0];
            star.y = starPosition[i][1];
            star.size = starPosition[i][2];
            stars.add(star);
        }
    }

    public float getStarScale() {
        return starScale;
    }

    public void setStarScale(float starScale) {
        this.starScale = starScale;
        postInvalidate();
    }

    public float getStarAlpha() {
        return starAlpha;
    }

    public void setStarAlpha(float starAlpha) {
        this.starAlpha = starAlpha;
        postInvalidate();
    }

    /**
     * 初始化動畫及繪制元素的對象
     */
    private void initAnimation() {
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.star_icon);
        paint = new Paint();
        paint.setAlpha(255);

        ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(this, "starScale", 0, 1, 0);
        scaleAnim.setInterpolator(new LinearInterpolator());
        scaleAnim.setDuration(1000);
        scaleAnim.setRepeatCount(-1);

        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, "starAlpha", 0, 255, 0);
        alphaAnim.setInterpolator(new LinearInterpolator());
        alphaAnim.setDuration(1000);
        alphaAnim.setRepeatCount(-1);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(scaleAnim, alphaAnim);
        animatorSet.playTogether(scaleAnim);
        animatorSet.start();
    }

    /**
     * 星星屬性
     */
    class Star {
        int x;
        int y;
        int size;
    }
}

從上面代碼中我們要注意,在ShiningStar 類中增加了兩個屬性starScale 和starAlpha 并且增加了setter和getter方法,在set中View面進(jìn)行刷新。這樣ObjectAnimator才可以對這兩個屬性進(jìn)行操作并且傳遞給界面。

結(jié)語:

Property Animation比較常用,本片主要總結(jié)了下知識點,示例并不全面。后面文章會有更多應(yīng)用。

上篇:動畫(Drawable Animation)(百度糯米加載動畫示例)

最后編輯于
?著作權(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)容