1.基本信息
- 屬性動畫的優(yōu)點
- 不再局限于View對象,無對象也可以進行動畫處理
- 不再局限于四種基本變換:平移,旋轉(zhuǎn),縮放,透明度
- 可以靈活的操作任意對象屬性,根據(jù)自己的業(yè)務(wù)來實現(xiàn)自己想要的結(jié)果
- 核心點
- ObjectAnimator 對象動畫
- ValueAnimator 值動畫
- PropertyValueHolder 用于同時執(zhí)行多個動畫
- TypeEvaluator 估值器
- AnimatorSet 動畫集合
- Interpolator 差值器
2.代碼示例
- 使用ObjectAnimator完成在一段時間內(nèi)透明度的變化
/**
* ObjectAnimator基本使用繼承子ValueAnimator
* 對對象v的alpha參數(shù)進行操作绝葡,alpha的值從1.0變到0.3
*
* @param v
*/
public void startObjectAnimatorAnim(View v) {
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0.3f);
//執(zhí)行事件
alphaAnim.setDuration(1000);
//延遲
alphaAnim.setStartDelay(300);
alphaAnim.start();
}
- 使用ValueAnimator完成在一段事件內(nèi)縮放
/**
* 在一段時間內(nèi)生成連續(xù)的值完成view的縮放
* @param v
*/
public void startValueAnimatorAnim(final View v) {
//不改變屬性大小诚些,只在一段事件內(nèi)生成連續(xù)的值
ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f);
animator.setDuration(500);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//百分比對應(yīng)的值
float value = (float) animation.getAnimatedValue();
Log.e("TAG", "onAnimationUpdate: " + value);
v.setScaleX(0.5f + value / 200);
v.setScaleY(0.5f + value / 200);
}
});
animator.start();
}
- 使用PropertyValueHolder完成上面的倆個動畫同時執(zhí)行
/**
* 一個動畫實現(xiàn)多個效果的變換
*
* @param v
*/
public void startPropertyValueHolderAnim(View v) {
PropertyValuesHolder alphaProper = PropertyValuesHolder.ofFloat("alpha", 0.5f, 1f);
PropertyValuesHolder scaleXProper = PropertyValuesHolder.ofFloat("scaleX", 0.5f, 1f);
PropertyValuesHolder scaleYProper = PropertyValuesHolder.ofFloat("scaleY", 0.5f, 1f);
ValueAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, alphaProper, scaleXProper, scaleYProper);
animator.setDuration(500);
animator.start();
}
- AnimatorSet多個動畫按制定順序執(zhí)行
/**
* 執(zhí)行多個動畫并控制動畫順序
*
* @param v
*/
public void startAnimatorSet(View v) {
ObjectAnimator animator1 = ObjectAnimator.ofFloat(v, "translationX", 0f, 100f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(v, "alpha", 0f, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(v, "scaleX", 0f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(500);
//動畫1蜘犁,2同時執(zhí)行
animatorSet.play(animator1).with(animator2);
//動畫2執(zhí)行完成后執(zhí)行動畫3
animatorSet.play(animator3).after(animator2);
animatorSet.start();
}
- animatorSet.play(animator1).with(animator2);動畫1和動畫2同時執(zhí)行
- animatorSet.play(animator3).after(animator2);動畫3在動畫2執(zhí)行完成后執(zhí)行
- animatorSet.playSequentially(animator1,animator2,animator3)動畫1,2,3按順序執(zhí)行
- animatorSet.playTogether(animator1,animator2,animator3)三個動畫同時執(zhí)行
- 估值器使用
估值器可以自定義變換規(guī)則,普通動畫是勻速執(zhí)行
/**
* 使用估值器實現(xiàn)重力下落
*
* @param v
*/
public void startEvaluator(final View v) {
ValueAnimator animator = new ValueAnimator();
animator.setDuration(3000);
animator.setObjectValues(new PointF(0, 0));
final PointF pointF = new PointF();
animator.setEvaluator(new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//fraction是運動中的勻速變化的值
//根據(jù)重力計算實際的運動y=vt=0.5*g*t*t
//g越大效果越明顯
pointF.x = 100 * (fraction * 5);
pointF.y = 0.5f * 300f * (fraction * 5) * (fraction * 5);
return pointF;
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF p = (PointF) animation.getAnimatedValue();
v.setX(p.x);
v.setY(p.y);
}
});
animator.start();
}
- 插值器
已經(jīng)定義好計算規(guī)則的估值器(API中已經(jīng)定義好了算法)
//加速查值器,參數(shù)越大甚牲,速度越來越快
animator.setInterpolator(new AccelerateInterpolator(10));
//減速差值起,和上面相反
animator.setInterpolator(new DecelerateInterpolator(10));
//先加速后減速插值器
animator.setInterpolator(new AccelerateDecelerateInterpolator());
//張力值絮宁,默認(rèn)為2含末,T越大,初始的偏移越大府适,而且速度越快
animator.setInterpolator(new AnticipateInterpolator(3));
//張力值tension羔飞,默認(rèn)為2,張力越大细溅,起始時和結(jié)束時的偏移越大
animator.setInterpolator(new AnticipateOvershootInterpolator(6));
//彈跳插值器
animator.setInterpolator(new BounceInterpolator());
//周期插值器
animator.setInterpolator(new CycleInterpolator(2));
//線性差值器,勻速
animator.setInterpolator(new LinearInterpolator());
3.實戰(zhàn)
使用屬性動畫完成下面效果
1.拆分動畫
- 剛進來時執(zhí)行旋轉(zhuǎn)動畫
- 數(shù)據(jù)加載完畢之后調(diào)用聚合逃逸動畫
- 聚合逃逸動畫完成之后,進行擴散
- 使用策略模式控制狀態(tài)轉(zhuǎn)變,一種狀態(tài)控制一個動畫
/**
* 策略模式(狀態(tài)模式),每一種狀態(tài)是一個繪制
*/
private abstract class SplashState {
public abstract void drawState(Canvas canvas);
public void cancle() {
}
}
/**
* 旋轉(zhuǎn)動畫
*/
private class RotateState extends SplashState {
@Override
public void drawState(Canvas canvas) {
}
}
/**
* 聚合動畫
*/
private class MerginState extends SplashState {
@Override
public void drawState(Canvas canvas) {
}
}
/**
* 擴散動畫
*/
private class ExpandState extends SplashState {
@Override
public void drawState(Canvas canvas) {
}
}
- 畫圓及完成旋轉(zhuǎn)動畫
- 使用值動畫計算360度旋轉(zhuǎn)過程的中間值,記錄當(dāng)前旋轉(zhuǎn)的角度
/**
* 旋轉(zhuǎn)動畫
*/
private class RotateState extends SplashState {
public RotateState() {
//0-360度
mAnimator = ValueAnimator.ofFloat(0f, (float) (Math.PI * 2));
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentRotationAngle = (float) animation.getAnimatedValue();
postInvalidate();
}
});
mAnimator.setDuration(mRotationDuration);
//無限循環(huán)
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
mAnimator.start();
}
@Override
public void drawState(Canvas canvas) {
drawBackground(canvas);
drawCircles(canvas);
}
}
- 通過計算每個小圓的初始角度及大圓旋轉(zhuǎn)的角度得出每個小圓旋轉(zhuǎn)過程中的角度
- 根據(jù)每個小圓所在的角度,根據(jù)勾股定理計算每個小圓的圓心位置
- 畫出每個小圓
/**
* 畫圓
*/
private void drawCircles(Canvas canvas) {
//x=r*cons(a)+centerX
//y=r*sina(a)+centerY
//1.周長
float rotationAngle = (float) (2 * Math.PI / mCircleColors.length);
for (int i = 0; i < mCircleColors.length; i++) {
//計算每個小圓的角度
double angle = i * rotationAngle + mCurrentRotationAngle;
//計算每個小圓的圓心
float cx = (float) (mCurrentRotationRadius * Math.cos(angle) + mCenterX);
float cy = (float) (mCurrentRotationRadius * Math.sin(angle) + mCenterY);
mPaint.setColor(mCircleColors[i]);
canvas.drawCircle(cx, cy, mCircleRadius, mPaint);
}
}
- 實現(xiàn)聚合動畫
- 實現(xiàn):改變大圓的半徑(根據(jù)值動畫值的變化改變半徑大小),使用張力差值起完成一次反彈效果
/**
* 聚合動畫
*/
private class MerginState extends SplashState {
public MerginState() {
mAnimator = ValueAnimator.ofFloat(mRotationRadius, 0);
mAnimator.setDuration(mRotationDuration);
//張力插值器褥傍,擴散反彈一下
mAnimator.setInterpolator(new OvershootInterpolator(10));
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentRotationRadius = (float) animation.getAnimatedValue();
postInvalidate();
}
});
mAnimator.start();
}
@Override
public void drawState(Canvas canvas) {
drawBackground(canvas);
drawCircles(canvas);
}
}
- 延遲5s執(zhí)行splashDisappear完成狀態(tài)的轉(zhuǎn)換
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mState == null) {
mState = new RotateState();
}
//先繪制旋轉(zhuǎn)
mState.drawState(canvas);
}
/**
* 進行狀態(tài)轉(zhuǎn)換
*/
public void splashDisappear() {
if (mState != null && mState instanceof RotateState) {
mState.cancle();
post(new Runnable() {
@Override
public void run() {
mState = new MerginState();
}
});
}
}
- 實現(xiàn)擴散動畫
-
實現(xiàn):創(chuàng)建一個空心圓,初始為小圓大小,最終直徑等于對角線大小,線條寬度等于對角線一半減去值動畫的中間值
/**
* 擴散動畫
*/
private class ExpandState extends SplashState {
public ExpandState() {
mAnimator = ValueAnimator.ofFloat(mCircleRadius, mDiagonalDist);
mAnimator.setDuration(mRotationDuration);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mHoleRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
mAnimator.start();
}
@Override
public void drawState(Canvas canvas) {
drawBackground(canvas);
}
}
/**
* 畫背景
*
* @param canvas
*/
private void drawBackground(Canvas canvas) {
if (mHoleRadius > 0) {
float strokeWidth = mDiagonalDist - mHoleRadius;
mPaintBackground.setStrokeWidth(strokeWidth);
float radius = mHoleRadius + strokeWidth / 2;
canvas.drawCircle(mCenterX, mCenterY, radius, mPaintBackground);
} else {
canvas.drawColor(mSplashBgColor);
}
}
最終效果如下
Demo地址