1. 前言
這是動畫的第三篇屬性動畫,屬性動畫是android動畫裏面用的最多的, 也是最重要的。android中三種動畫的使用文章以下:java
2. 介紹
3. 使用
3.1 ValueAnimator使用
先來一張動畫效果圖android
3.1.1 ValueAnimator 介紹
3.1.2 ofInt、ofFloat、ofArgb
經過調用ValueAnimator.ofInt這個方法, 咱們就能構建一個整型的ValueAnimator,以下:git
private void valueAnimatorOfInt() {
//獲取到屏幕寬度
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
//起始值爲btn最開始的座標的x位置, 結束值爲 屏幕的最右邊,
ValueAnimator valueAnimator = ValueAnimator.ofInt((int) btnOfInt.getTranslationX(), widthPixels);
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(2);
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.setStartDelay(500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int currentValue = (int) valueAnimator.getAnimatedValue();
btnOfInt.setTranslationX(currentValue);
System.out.println("current value:" + currentValue);
}
});
valueAnimator.start();
}
複製代碼
解釋:github
使用十分簡單,ValueAnimator.ofFloat,ValueAnimator.ofArgb 都是同理,傳入開始值和結束值, 而後監聽數值的變化, 設置給你要進行動畫的view。 下面定義了兩個方法,是對ofFloat,ofArgb的使用:canvas
private void valueAnimatorOfFloat() {
//獲取到屏幕寬度
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
//起始值爲btn最開始的寬度, 結束值爲 屏幕的寬度。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(btnofFloatWidth,widthPixels);
valueAnimator.setDuration(2000);
// valueAnimator.setRepeatCount(2);
// valueAnimator.setRepeatMode(ValueAnimator.RESTART);
// valueAnimator.setStartDelay(500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float currentValue = (float) valueAnimator.getAnimatedValue();
btnOfFloat.getLayoutParams().width = (int) currentValue;
//從新繪製
btnOfFloat.requestLayout();
System.out.println("current value:" + currentValue);
}
});
valueAnimator.start();
}
private void valueOfRGB(){
ValueAnimator valueAnimator = ValueAnimator.ofArgb(Color.BLUE, Color.RED);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int currentValue = (int) valueAnimator.getAnimatedValue();
btnOfRgb.setBackgroundColor(currentValue);
System.out.println("current value:" + currentValue);
}
});
valueAnimator.start();
}
複製代碼
3.1.3 ValueAnimator.ofObject
在介紹中說過, 屬性動畫能夠做用在任意對象。 好比我有一個Point類,類中有x,y兩個屬性用來表示座標。 經過Point建立兩個對象,一個pointA,PointB。如何從pointA變化到pointB呢?bash
public class MyView extends View {
private float RADIUS = 50f;
private Point currentPoint;
private Paint mPaint ;
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
currentPoint = new Point(RADIUS,RADIUS);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCircle(canvas);
}
private void drawCircle(Canvas canvas){
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x,y,RADIUS,mPaint);
}
public void startAnimation (){
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(),startPoint,endPoint);
valueAnimator.setDuration(5000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Point point = (Point)valueAnimator.getAnimatedValue();
currentPoint = point;
invalidate();
System.out.println("current point,x:"+currentPoint.getX()+"y:"+currentPoint.getY());
}
});
valueAnimator.start();
}
}
複製代碼
自定義了一個view畫一個圓。startAnimation方法可使這個圓從startPoint移動到endPoint。dom
解釋:ide
ValueAnimator.ofObject: 經過ofObject建立一個動畫對象, 傳入估值器、開始對象和結束對象。post
估值器是個什麼東西?
估值器就是用來描述動畫邏輯的,說白了就是計算在對應的時間點上, 當前的值是多少。 以前的ofInt、ofFloat、ofArgb 這些, 系統都幫咱們寫好了,計算好了。 可是若是是從一個任意對象變化到另外一個對象。 就須要咱們本身寫估值器了。動畫
/**
* point 估值器
*/
public class PointEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
Point point = new Point(x, y);
return point;
}
}
複製代碼
實現TypeEvaluator接口就好了, 接口會傳當前動畫進度、開始對象和結束對象進來。 你只須要根據這三個東西來計算出當前動畫進度的對象並返回就能夠了。
3.1.4 PropertyValuesHolder
上面都是對一個屬性變化進行動畫, 若是是多個呢,好比我要改一個按鈕的寬和高。 那就要用到PropertyValuesHolder。
private void valueOfPropertyValues(){
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
int heightPixels = displayMetrics.heightPixels;
PropertyValuesHolder holder1 = PropertyValuesHolder.ofInt("width", btnWidth, widthPixels);
PropertyValuesHolder holder2 =PropertyValuesHolder.ofInt("height",btnHeight,heightPixels-btnOfValuesProperty.getTop());
ValueAnimator valueAnimator = ValueAnimator.ofPropertyValuesHolder(holder1, holder2);
valueAnimator.setDuration(5000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int width = (int) valueAnimator.getAnimatedValue("width");
int height = (int) valueAnimator.getAnimatedValue("height");
btnOfValuesProperty.getLayoutParams().width = width;
btnOfValuesProperty.getLayoutParams().height = height;
btnOfValuesProperty.requestLayout();
System.out.println("width:"+width+"height:"+height);
}
});
valueAnimator.start();
}
複製代碼
解釋:
PropertyValuesHolder.ofInt: 和剛剛的ValueAnimator.ofInt 同樣, 都是傳入一個開始值和結束值。建立出來一個要變化的屬性對象。
ValueAnimator.ofPropertyValuesHolder: 把建立的多個要變化的屬性對象傳進來,構建出一個動畫對象。
valueAnimator.getAnimatedValue: 經過屬性名, 獲取到屬性的當前值。拿到多個屬性值後, 咱們就能夠來從新設置按鈕的寬高造成動畫啦。
3.1.4 ValueAnimator使用總結
咱們傳入一個開始值和結束值給到ValueAnimator, 它會幫咱們計算出在當前時間,這個值是多少。 咱們經過監聽獲取到這個值,從新設置給view等對象,讓view重繪。這就是ValueAnimator作動畫的原理。
3.2 ObjectAnimator使用
上面說的ValueAnimator咱們是經過監聽值的變化來給view設置屬性,從新繪製,完成動畫。 那麼ObjectAnimator就是咱們把屬性名給它,讓他本身來根據屬性值的變化完成動畫。
3.2.1 translate、rotate、scale、alpha
好比咱們要經過ObjectAnimator來改變view的屬性,讓view平移、選擇、縮放、透明:
private void translate() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnTranslate, "translationX", 0, 500, 200);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
private void rotate() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnRotate, "rotation", 0, 200, 300);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
private void scale() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnScale, "ScaleX", 0f, 0.5f, 1.1f);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
private void alpha() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnAlpha, "Alpha", 0, 0.5f, 1f);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
複製代碼
解釋:
3.2.2 自定義屬性
上面那些是view本地有自帶的setTranslationX、setRotation等方法,才能夠經過translationX、rotataion這些屬性來完成動畫。 若是咱們自定義的view,要變化其餘屬性呢,好比一個進度條, 經過變化進度屬性值來完成進度的動畫。那就須要咱們本身定義屬性和屬性對應的setter方法,並在setter方法中,重繪view。
public class ProgressView extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float progress = 0;
private float RADIUS = 80;
public ProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public float getProgress() {
return progress;
}
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float centerX = getWidth()/2;
float centerY = getHeight()/2;
mPaint.setColor(Color.RED);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(25);
mPaint.setStyle(Paint.Style.STROKE);
RectF rectF = new RectF(centerX - RADIUS, centerY - RADIUS, centerX + RADIUS, centerY + RADIUS);
canvas.drawArc(rectF,0,3.6f*progress,false,mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText((int) progress + "%", centerX, centerY - (mPaint.ascent() + mPaint.descent()) / 2, mPaint);
}
}
複製代碼
private void custom() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(progressView, "progress", 0, 90);
objectAnimator.setDuration(5000);
objectAnimator.setInterpolator(new FastOutSlowInInterpolator());
objectAnimator.start();
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
objectAnimator.addListener(new AnimatorListenerAdapter() {
// @Override
// public void onAnimationStart(Animator animation) {
// super.onAnimationStart(animation);
// }
});
}
複製代碼
這樣咱們就能夠對咱們自定義view中的屬性變化並完成動畫了。
3.2.2 指定動畫的關鍵幀
這裏的關鍵幀就是用來指定,在某一幀的時候的屬性。 好比動畫到一半時候的那一幀, 我要把屬性設置成什麼什麼。下面例子仍是用上面那個進度條, 當動畫到一半的時候,把進度設置成100。
private void keyFrame() {
//設置關鍵幀, 第一個參數是 完成度, 第二個參數是 屬性值, 好比當完成度一半的時候(0.5),屬性值(progress)給100;
Keyframe keyframe = Keyframe.ofFloat(0, 0);
Keyframe keyframe1 = Keyframe.ofFloat(0.5f, 100);
Keyframe keyframe2 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe, keyframe1, keyframe2);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(progressView, holder);
objectAnimator.setDuration(5000);
objectAnimator.start();
}
複製代碼
解釋:
3.3 ViewPropertyAnimator使用
ViewPropertyAnimator, 是直接經過view的animate來對view的一些自帶屬性進行動畫。 animate返回的對象就是ViewPropertyAnimator類型。
private void viewProperty(){
btnViewProperty.animate().alpha(0).setDuration(2000).rotation(360).translationX(300);
}
複製代碼
3.4 組合動畫
不少時候, 單個動畫知足不了需求。 須要將多個動畫變成一連串的組合動畫。 好比講移動、旋轉、透明組合起來, 一塊兒或者前後完成動畫。
private void animatorSet() {
// AnimatorSet.playTogether(Animator... anim) : 將動畫組合一塊兒執行
// AnimatorSet.playSequentially(Animator... anim) : 將動畫組合有序執行
// AnimatorSet.play(Animator anim) :播放當前動畫
// AnimatorSet.after(long delay) :將現有動畫延遲x毫秒後執行
// AnimatorSet.with(Animator anim) :將現有動畫和傳入的動畫同時執行
// AnimatorSet.after(Animator anim) :將現有動畫插入到傳入的動畫以後執行
// AnimatorSet.before(Animator anim) : 將現有動畫插入到傳入的動畫以前執行
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
ObjectAnimator translationX = ObjectAnimator.ofFloat(btnSet, "translationX", 0, widthPixels);
ObjectAnimator rotation = ObjectAnimator.ofFloat(btnSet, "rotation", 0, 360);
ObjectAnimator alpha = ObjectAnimator.ofFloat(btnSet, "alpha", 1, 0, 1);
AnimatorSet animatorSet = new AnimatorSet();
// animatorSet.playTogether(translationX,rotation,alpha);
// animatorSet.playSequentially();
animatorSet.play(rotation).with(alpha).before(translationX);
animatorSet.setDuration(5000);
animatorSet.setInterpolator(new LinearInterpolator());
animatorSet.start();
}
複製代碼
解釋:
3.5 xml中編寫動畫
在/res/animator/目錄下新建xml文件:
<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="sequentially" >
<objectAnimator android:duration="2000" android:propertyName="translationX" android:valueFrom="-200" android:valueTo="0" android:valueType="floatType" >
</objectAnimator>
<set android:ordering="together" >
<objectAnimator android:duration="3000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" android:valueType="floatType" >
</objectAnimator>
<set android:ordering="sequentially" >
<objectAnimator android:duration="1500" android:propertyName="alpha" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" >
</objectAnimator>
<objectAnimator android:duration="1500" android:propertyName="alpha" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" >
</objectAnimator>
</set>
</set>
</set>
<!-- 將一個視圖先從屏幕外移動進屏幕,而後開始旋轉360度,旋轉的同時進行淡入淡出操做-->
複製代碼
xml中使用的比較少,這裏也不詳細寫。能夠參考下面郭霖文章寫的。
4.總結
5. 完整demo地址
6. 參考文章
7. 歷史文章目錄