Android動畫之ObjectAnimator實現補間動畫和ObjectAnimator自定義屬性

1 ObjectAnimator 概述

前面講解了ValueAnimator和估值器,ValueAnimator只能對數值進行計算,要實現動畫需要監聽動畫,然後獲取數值,自己操作對象。不知道大家的感覺如何,我有兩個兩個感覺,一是這個動畫有點複雜,另一個感覺是雖然叫做屬性對象,但是完全沒有感受到哪裏跟屬性有關。本篇文章主要講解ObjectAnimator對象,這個對象繼承自ValueAnimator,可以通過改變對象的屬性,實現動畫,是不是感覺ObjectAnimator叫做屬性對象更合適。

在這裏插入圖片描述
ObjectAnimator繼承自ValueAnimator,也是從API11纔開始提供。

ValueAnimator類提供了把動畫中的屬性設置給目標對象的能力,只不過需要我們設置監聽自己進行設置。ObjectAnimator可以設置動畫目標對象(構造函數可以直接傳入),構造函數中提供了將要作用於目標對象的屬性名,ObjectAnimator運行過程中會把提供的屬性利用目標對象提供的set函數設置給目標對象,有時也會調用目標對象的get函數獲取屬性值。簡單說就是ObjectAnimator通過不斷控制值的變化,再不斷自動賦給對象的屬性(調用目標對象的setXXX函數),從而實現動畫效果。

屬性動畫原理:
屬性動畫並不是真正通過改變對象的屬性來實現動畫,而是通過調用目標對象指定的setXxx方法,其中xxx就是指定的屬性名,對象不一定有xxx這個屬性,只要有setXxx這個方法就可以。ObjectAnimator動畫過程中會調用SetXxx函數設置xxx的值,然後其內部會主動調用invalidate()函數進行不停地重繪,這樣就實現了動畫效果。

ObjectAnimator類似ValueAnimator,不但可以直接利用代碼生成,也可以利用xml文件實例化,xml方式不常用。
XML定義ObjectAnimator的標籤爲objectAnimator,API23以後也可以使用PropertyValuesHolder,具體使用方式在講解ValueAnimator時已經講解,這裏不再重複。

ObjectAnimator實現動畫的of方法

ofArgb(Object target, String propertyName, int... values)
ofArgb(T target, Property<T, Integer> property, int... values)
ofFloat(Object target, String xPropertyName, String yPropertyName, Path path)
ofFloat(T target, Property<T, Float> property, float... values)
ofFloat(T target, Property<T, Float> xProperty, Property<T, Float> yProperty, Path path)
ofFloat(Object target, String propertyName, float... values)

ofInt(T target, Property<T, Integer> xProperty, Property<T, Integer> yProperty, Path path)
ofInt(T target, Property<T, Integer> property, int... values)
ofInt(Object target, String propertyName, int... values)
ofInt(Object target, String xPropertyName, String yPropertyName, Path path)

ofMultiFloat(Object target, String propertyName, float[][] values)
ofMultiFloat(Object target, String propertyName, Path path)
ofMultiFloat(Object target, String propertyName, TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, T... values)
ofMultiInt(Object target, String propertyName, int[][] values)
ofMultiInt(Object target, String propertyName, Path path)
ofMultiInt(Object target, String propertyName, TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, T... values)

ofObject(T target, Property<T, V> property, TypeEvaluator<V> evaluator, V... values)
ofObject(Object target, String propertyName, TypeConverter<PointF, ?> converter, Path path)
ofObject(T target, Property<T, V> property, TypeConverter<PointF, V> converter, Path path)
ofObject(T target, Property<T, P> property, TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values)
ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values)

ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)

2利用ObjectAnimator實現補間動畫效果

2.1 平移動畫

View有setTranslationX,setTranslationY實現座標的改變
setTranslationX(float translationX) :以當前控件爲原點,在x軸上移動
setTranslationY(float translationY) :以當前控件爲原點,在Y軸上移動

ObjectAnimator實現平移:
向X軸正方向移動:

objectAnimator = ObjectAnimator.ofFloat(textView, "translationX", 100, 200, 300,400,500);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在這裏插入圖片描述
Y軸方向移動不在演示

2.2 透明度

View有setAlpha函數控制透明度
ObjectAnimator實現透明度變化:

objectAnimator = ObjectAnimator.ofFloat(textView, "alpha", 0.1f,1.0f);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在這裏插入圖片描述

2.3 縮放

View有setScaleX(float scaleX)和setScaleY(float scaleY)函數對View進行縮放。
ObjectAnimator實現縮放

objectAnimator = ObjectAnimator.ofFloat(textView, "scaleX", 0.1f,1.0f,2.0f,1.0f);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在這裏插入圖片描述

2.4 旋轉

View有setRotationX(float rotationX)和setRotationY(float rotationY),setRotation(rotation)函數設置旋轉,
setRotationX:繞X軸旋轉
setRotationY:繞Y軸旋轉
setRotation: 繞中心旋轉

ObjectAnimator實現旋轉

objectAnimator = ObjectAnimator.ofFloat(textView, "rotation", 0,270);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new LinearInterpolator());

在這裏插入圖片描述

3 ObjectAnimator動畫注意事項:重要

總結來自:https://developer.android.google.cn/guide/topics/graphics/prop-animation#java
動畫一些特性:

  • duration 動畫運行時長,如果不設置默認300ms
  • interpolation:設置動畫運行過程中對應的動畫完成狀態(設置動畫運行速率,類似動畫設置了1000ms,可以讓動畫在運行到100ms時就展示動畫完成時的狀態)
  • 動畫刷新頻率,默認是每10ms刷新一次,但也跟系統忙碌程度有關,如果系統資源佔用嚴重可能時間會延長。

重要:一下內容來自androidDeveloper,非常重要請大家關注
屬性動畫getXxx(),setXxx()函數和屬性xxx的規則說明:

  • 如果ObjectAnimator想操作對象的foo屬性實現動畫操作,對象必須有相應的setFoo函數,
    因爲ObjectAnimator會自動根據foo屬性對應的setFoo函數去更新屬性值。所以可以推測出ObjectAnimator會自動把屬性轉化成對應的set函數,會強制大寫第一個字母,然後反射得到set函數,進行調用,所以ObjectAnimator初始化時屬性首字母大小寫無所謂,關鍵是除了首字母其他一定要和set函數對應。

  • 上面我們知道了對象setter函數的作用,那麼getter函數有什麼用處呢,ObjectAnimator指定values時,可以指定多個value,如果我們初始化時只指定了一個值,ObjectAnimator會把這個值作爲動畫結束狀態的值,此時會調用getter函數作爲動畫初始狀態的值。

  • 動畫目標對象getter和setter函數的參數類型和ObjectAnimator設置動畫開始和結束值的類型必須相同。

  • ObjectAnimator內部會主動調用目標對象的setter方法,但是這並不會導致view的重繪,需要你在setter方法中主動調用invalidate方法或者設置動畫監聽函數,在onAnimationUpdate的回調中調用invalidate方法。如果你要自己定義對象的setter方法,就要主動調用invalidate方法。

4 自定義ObjectAnimator屬性

上面把view已經存在的平移,旋轉,縮放,透明度屬性利用ObjectAnimator進行了實現,接着將演示自定義ObjectAnimator屬性的操作,通過上面的分析知道ObjectAnimator重要的點是屬性和設置屬性的set函數,以及主動調用invalidate函數,下面會通過一個例子來實現自定義ObjectAnimator屬性的過程。
自定義view

public class ViewDemo22 extends View {
    private int color = Color.GREEN;
    private int radius = 100;

    private Paint mPaint;

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
        mPaint.setColor(color);
        invalidate();
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
        invalidate();
    }

    public ViewDemo22(Context context) {
        this(context,null,0);
    }

    public ViewDemo22(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ViewDemo22(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(color);
        mPaint.setStrokeWidth(5);
        mPaint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(getMeasuredHeight()/2,getMeasuredHeight()/2,radius,mPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (width < 200){
            width = 200;
        }

        if (height < 200){
            height = 200;
        }

        if (width < height){
            setMeasuredDimension(height,height);
        }else{
            setMeasuredDimension(width,width);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }
}

佈局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

<com.ldx.canvasdrawdemo.ViewDemo22
    android:id="@+id/viewdemo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

</android.support.constraint.ConstraintLayout>
setContentView(R.layout.activity_main);
viewDemo22 = findViewById(R.id.viewdemo);

ObjectAnimator objectAnimator = ObjectAnimator.ofInt(viewDemo22, "radius", 50, 300);
objectAnimator.setDuration(1000);
objectAnimator.setInterpolator(new LinearInterpolator());
objectAnimator.setRepeatCount(-1);
objectAnimator.start();

在這裏插入圖片描述

改變顏色,沒有設置插值器,只是簡單數據改變:

ObjectAnimator objectAnimator = ObjectAnimator.ofInt(viewDemo22, "color", Color.RED, Color.GREEN);
objectAnimator.setDuration(1000);
objectAnimator.setInterpolator(new LinearInterpolator());
objectAnimator.setRepeatCount(-1);
objectAnimator.start();

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章