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();