概述:
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)建屬性動畫的方法。涉及到的類如下圖所示:

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提供了下面這些賦值器。

//這是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提供了下面這些插值器,基本上見名知意。

//這是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)下后效果如下圖:

實現(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)用。