@作者 : 西野奈留
@博客:http://blog.csdn.net/narunishino
-2016/4/11-
项目来自这位大神:
http://blog.csdn.net/caroline_wendy/article/details/50526770
我只是添加了学习的注释,如下:
3个类:LikeButtonView , CircleView , DotsView
CircleView
package com.atozmak.tabhostviewpagerdemo.frgm07;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Property;
import android.view.View;
import com.atozmak.tabhostviewpagerdemo.mainActivity.LogUtils;
/** * 圆形视图, 外圆是实心圆圈, 颜色渐变; 内圆是擦除效果. * <p/> * Created by Mak on 2016/4/8. */
public class CircleView extends View {
public static final String TAG = LogUtils.makLogTag("CircleView");
private static final int START_COLOR_RED = 0xffff5722;//红色 http://rgb.phpddt.com/
private static final int END_COLOR_ORANGE = 0xffffc107;//橙色 http://rgb.phpddt.com/
private ArgbEvaluator mArgbEvaluator;//颜色值计算器。
private Paint mCirclePaint;//圆形试图
private Paint mMaskPaint;//掩盖视图
private Canvas mTempCanvas;//中间画布
private Bitmap mTempBitmap;//中间画图
private int mMaxCircleSize;//最大圆环大小(半径)
private float mOuterCircleRadiusProgress;//初始值默认为0.0
private float mInnerCircleRadiusProgress;//初始值默认为0.0
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//初始化, 外圆使用实心画笔(Paint), 内圆使用擦除画笔. ArgbEvaluator控制颜色变换.
private void init() {
mCirclePaint = new Paint();
mCirclePaint.setStyle(Paint.Style.FILL);
mMaskPaint = new Paint();//消失的效果
//橡皮擦的效果。
mMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mArgbEvaluator = new ArgbEvaluator();
}
//---------------------------------------------------
/** * onMeasure结束后会调用onSizeChanged。 * <p/> * * @param w Current width of this view. * @param h Current height of this view. * @param oldw Old width of this view. * @param oldh Old height of this view. */
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//圆的半径最大不超过本view宽度的一般。
mMaxCircleSize = w / 2;
//Returns a mutable bitmap with the specified width and height.
mTempBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
//* Construct a canvas with the specified bitmap to draw into. The bitmap must be mutable.
mTempCanvas = new Canvas(mTempBitmap);
}
//---------------------------------------------------
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/** * 画一个透明的背景。不画的话效果也是一样,不知道作者为什么会这样做。 * * 如果是用canvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR);就会得到黑色的背景。 * 即使在xml文件中也改变不了背景色。还是黑色 * * mTempCanvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR); * * 如果没有这句的话,会出现:双击的时候会卡住一个圆,没有被擦除。 */
mTempCanvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR);
mTempCanvas.drawCircle(
getWidth() / 2,
getHeight() / 2,
//变化值<0~1> * 半径 ,即,圆将由小变大,最大至半径为mMaxCircleSize。
mOuterCircleRadiusProgress * mMaxCircleSize,
mCirclePaint
);
//mMaskPaint只会擦除本view里面的底色,本view外的颜色不受影响。
mTempCanvas.drawCircle(
getWidth() / 2,
getHeight() / 2,
mInnerCircleRadiusProgress * mMaxCircleSize,
mMaskPaint
);
/** * Canvas(bitmap) 与 canvas.setBitmap(bitmap)中的bitmap是Canvas的mBitmap,直接操作/修改的对象。 * canvas.drawBitmap(bitmap)中的bitmap是源bitmap,draw时,不对源bitmap进行写操作, */
canvas.drawBitmap(mTempBitmap, 0, 0, null);
// Log.v(TAG, "onDraw——————" + "mOuterCircleRadiusProgress= " + mOuterCircleRadiusProgress);
}
//---------------------------------------------------
public float getOuterCircleRadiusProgress() {
return mOuterCircleRadiusProgress;
}
public void setOuterCircleRadiusProgress(float outerCircleRadiusProgress) {
mOuterCircleRadiusProgress = outerCircleRadiusProgress;
updateCircleColor();
//因为这是一个动态的view,所以需要通知view在数值更新时就要更新view。
postInvalidate();
// Log.v(TAG, "updateCircleColor>>>>postInvalidate>>>>>");
}
// 更新圆圈的颜色变化
private void updateCircleColor() {
/** * 0.5到1颜色渐变 * * 如果【mOuterCircleRadiusProgress】在【0.5到1】之间的话, * 就返回【mOuterCircleRadiusProgress】,否则返回0.5或者1. * * 流程:【mOuterCircleRadiusProgress】<0.1~1>,【colorProgress】<0.5~1> */
float colorProgress = (float) ProAnimUtils.clamp(
mOuterCircleRadiusProgress, 0.5, 1
);
/** * public class ArgbEvaluator implements TypeEvaluator * public Object evaluate(float fraction, Object startValue, Object endValue) * * 【colorProgress】是一个【fraction】 */
//转换映射控件
colorProgress = (float) ProAnimUtils.mapValueFromRangeToRange(
colorProgress, 0.5f, 1f, 0f, 1f
);
/** * 【mOuterCircleRadiusProgress】在0.5之前,【mCirclePaint.setColor】都是红色,之后会由红色0向黄色过度。 * 即先红色一会,再转黄色。 * 【mapValueFromRangeToRange】是使得颜色过度平滑<0~1>,而不是已经转了一般黄色的红色想黄色转<0.5~1>. * 把擦除效果的圆屏蔽了就能看到效果了。 */
mCirclePaint.setColor((Integer) mArgbEvaluator.evaluate(colorProgress, START_COLOR_RED, END_COLOR_ORANGE));
}
/** * get,set例子。 * <p/> * private static class MyView{ * private View mTarget; * private MyView(View mTarget){ * this.mTarget=mTarget; * } * public int getWidth(){ * return mTarget.getLayoutParams().width; * } * public void setWidth(int width){ * mTarget.getLayoutParams().width=width; * mTarget.requestLayout(); * } * } * 使用时只需要操纵包类就可以调用get,set方法: * MyView mMyView=new MyView(mButton); * ObjectAnimator.ofInt(mMyView,"width",500).setDuration(500).start(); */
public float getInnerCircleRadiusProgress() {
return mInnerCircleRadiusProgress;
}
public void setInnerCircleRadiusProgress(float innerCircleRadiusProgress) {
mInnerCircleRadiusProgress = innerCircleRadiusProgress;
// 从【ObjectAnimation.ofFloat】中获取到【开始值】和【终值】,
// 通过【Property】传递到【setInnerCircleRadiusProgress】,
// 【setInnerCircleRadiusProgress】把值传给【mInnerCircleRadiusProgress】,
// 然后通知系统更新view。
postInvalidate();
}
//---------------------------------------------------
/** * (似乎是)Property作为中介传递数据。 * <p/> * 问题是:ObjectAnimator是如何获取自定义属性名的。 * <p/> * public static <T> ObjectAnimator ofFloat( T target, Property<T, Float> property, float... values) * <p/> * ObjectAnimator.ofFloat(mCvCircle, CircleView.OUTER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f); * ObjectAnimator.ofFloat(mCvCircle, CircleView.INNER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f); * <p/> * <T> The class on which the property is declared. * <V> The type that this property represents. */
public static final Property<CircleView, Float> INNER_CIRCLE_RADIUS_PROGRESS =
//public Property(Class<V> type, String name)
new Property<CircleView, Float>(Float.class, "innerCircleRadiusProgress") {
// public abstract V get(T object);
@Override
public Float get(CircleView object) {
return object.getInnerCircleRadiusProgress();
}
/** * * public void set(T object, V value) * * @param object // * @param value 这个value是从哪里来的。(应该是)ObjectAnimator.ofFloat的时候传进去的value。 */
@Override
public void set(CircleView object, Float value) {
object.setInnerCircleRadiusProgress(value);
}
};
public static final Property<CircleView, Float> OUTER_CIRCLE_RADIUS_PROGRESS =
new Property<CircleView, Float>(Float.class, "outerCircleRadiusProgress") {
@Override
public Float get(CircleView object) {
return object.getOuterCircleRadiusProgress();
}
@Override
public void set(CircleView object, Float value) {
object.setOuterCircleRadiusProgress(value);
}
};
//---------------------------------------------------
}
DotsView
package com.atozmak.tabhostviewpagerdemo.frgm07;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Property;
import android.view.View;
/** * 发散的点, 由大点小点组成, 两类点排列和颜色均错开, 速度先慢后快向外发射. * <p/> * Created by Mak on 2016/4/8. */
public class DotsView extends View {
private static final int DOTS_COUNT = 7;
private static final int OUTER_DOTS_POSITION_ANGLE = 51;
private static final int COLOR_1 = 0xffffc107;//橙色
private static final int COLOR_2 = 0xffff9800;//橙带红
private static final int COLOR_3 = 0xffff5722;//橙带更红
private static final int COLOR_4 = 0xfff44336;//红
private final Paint[] mCirclePaints = new Paint[4];
private int mCenterX;
private int mCenterY;
private float mMaxOuterDotsRadius;// 最大外圈的半径
private float mMaxInnerDotsRadius;// 最大内圈的半径
private float mMaxDotSize;// 圆圈的最大尺寸
private float mCurrentProgress = 0;// 当前进度, 核心参数 , <0.0f~1.0f>
private float mCurrentRadius1 = 0;// 外圈点的半径 ,圈的半径,不是圆点的半径
private float mCurrentDotSize1 = 0;// 外圈点的大小
private float mCurrentRadius2 = 0;
private float mCurrentDotSize2 = 0;
private ArgbEvaluator argbEvaluator = new ArgbEvaluator();
public DotsView(Context context) {
super(context);
init();
}
public DotsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public DotsView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
for (int i = 0; i < mCirclePaints.length; i++) {
mCirclePaints[i] = new Paint();
mCirclePaints[i].setStyle(Paint.Style.FILL);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCenterX = w / 2;
mCenterY = h / 2;
mMaxDotSize = 20;
/** * 保证弹射出来的圆点能不会弹到屏幕外(看不见), * 所以圆点运动的最大半径是view的宽度减去圆点的直径。 */
mMaxOuterDotsRadius = w / 2 - mMaxDotSize * 2;
mMaxInnerDotsRadius = 0.8f * mMaxOuterDotsRadius;
}
//------------------------------------------
@Override
protected void onDraw(Canvas canvas) {
drawOuterDotsFrame(canvas);
drawInnerDotsFrame(canvas);
}
private void drawOuterDotsFrame(Canvas canvas) {
/** * 计算出位置,在各个位置绘制圆点。 */
for (int i = 0; i < DOTS_COUNT; i++) {
//Math.cos, in radians
//PI是弧度的180度。
int cX = (int) (mCenterX + mCurrentRadius1 * Math.cos(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
int cY = (int) (mCenterX + mCurrentRadius1 * Math.sin(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
canvas.drawCircle(cX, cY, mCurrentDotSize1, mCirclePaints[i % mCirclePaints.length]);
}
}
private void drawInnerDotsFrame(Canvas canvas) {
for (int i = 0; i < DOTS_COUNT; i++) {
int cX = (int) (mCenterX + mCurrentRadius2 * Math.cos((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
int cY = (int) (mCenterY + mCurrentRadius2 * Math.sin((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
//i+1 确保颜色不同
canvas.drawCircle(cX, cY, mCurrentDotSize2, mCirclePaints[(i + 1) % mCirclePaints.length]);
}
}
//------------------------------------------
public void setCurrentProgress(float currentProgress) {
mCurrentProgress = currentProgress;
updateInnerDotsPosition();
updateOuterDotsPosition();
updateDotsPaints();
updateDotsAlpha();
postInvalidate();
}
public float getCurrentProgress() {
return mCurrentProgress;
}
//--------------------------------------
private void updateDotsAlpha() {
float progress = (float) ProAnimUtils.clamp(mCurrentProgress, 0.6f, 1f); // 最小0.6, 最大1
int alpha = (int) ProAnimUtils.mapValueFromRangeToRange(progress, 0.6f, 1f, 255, 0); // 直至消失
mCirclePaints[0].setAlpha(alpha);
mCirclePaints[1].setAlpha(alpha);
mCirclePaints[2].setAlpha(alpha);
mCirclePaints[3].setAlpha(alpha);
}
//颜色变化
private void updateDotsPaints() {
if (mCurrentProgress < 0.5f) {
float progress = (float) ProAnimUtils.mapValueFromRangeToRange(mCurrentProgress, 0f, 0.5f, 0, 1f);
// mCirclePaints[0].setColor(0xff000000);
mCirclePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
mCirclePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
mCirclePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
mCirclePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
} else {
float progress = (float) ProAnimUtils.mapValueFromRangeToRange(mCurrentProgress, 0.5f, 1f, 0, 1f);
mCirclePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
mCirclePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
mCirclePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
mCirclePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
}
}
//--------------------------------------
private void updateOuterDotsPosition() {
// 半径先走的快, 后走的慢
//private float mCurrentProgress = 0;// 当前进度, 核心参数
if (mCurrentProgress < 0.3f) {
/** * mCurrentRadius1是圈的半径,不是圆点的半径。 * * 用前30%的时间,走80%的距离。 * * 【mCurrentProgress(时间值)】----->【mCurrentRadius1(半径值)】 */
mCurrentRadius1 = (float) ProAnimUtils.mapValueFromRangeToRange(
mCurrentProgress, 0.0f, 0.3f, 0, mMaxOuterDotsRadius * 0.8f);
} else {
/** * 用剩下的70%的时间,走完剩下的20%的距离。 */
mCurrentRadius1 = (float) ProAnimUtils.mapValueFromRangeToRange(
mCurrentProgress, 0.3f, 1f, 0.8f * mMaxOuterDotsRadius, mMaxOuterDotsRadius);
}
// 圆点的大小, 前70%的时间为mMaxDotSize, 后30%的时间逐渐缩小为0.
if (mCurrentProgress < 0.7f) {
mCurrentDotSize1 = mMaxDotSize;
} else {
mCurrentDotSize1 = (float) ProAnimUtils.mapValueFromRangeToRange(
mCurrentProgress, 0.7f, 1f, mMaxDotSize, 0);
}
}
private void updateInnerDotsPosition() {
if (mCurrentProgress < 0.3f) {
//前30%时间,走完全程。
this.mCurrentRadius2 = (float) ProAnimUtils.mapValueFromRangeToRange(
mCurrentProgress, 0, 0.3f, 0.0f, mMaxInnerDotsRadius);
} else {
//剩下的时间不动。
this.mCurrentRadius2 = mMaxInnerDotsRadius;
}
if (mCurrentProgress < 0.2) {
//前20%的时间,圆点大小为 mMaxDotSize。
this.mCurrentDotSize2 = mMaxDotSize;
} else if (mCurrentProgress < 0.5) {
//20%到50%的时间内,大小由 mMaxDotSize 缩小成 30%的大小。
this.mCurrentDotSize2 = (float) ProAnimUtils.mapValueFromRangeToRange(
mCurrentProgress, 0.2f, 0.5f, mMaxDotSize, 0.3 * mMaxDotSize);
} else {
//50%到结束的时间,大小由 30%的大小 缩小成 0。
this.mCurrentDotSize2 = (float) ProAnimUtils.mapValueFromRangeToRange(
mCurrentProgress, 0.5f, 1f, mMaxDotSize * 0.3f, 0);
}
}
//--------------------------------------
public static final Property<DotsView, Float> DOTS_PROGRESS
= new Property<DotsView, Float>(Float.class, "dotsProgress") {
@Override
public Float get(DotsView object) {
return object.getCurrentProgress();
}
@Override
public void set(DotsView object, Float value) {
object.setCurrentProgress(value);
}
};
}
LikeButtonView
package com.atozmak.tabhostviewpagerdemo.frgm07;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.atozmak.tabhostviewpagerdemo.R;
/** * http://www.wangchenlong.org/2016/03/22/1603/224-star-explode-anim/ */
public class LikeButtonView extends FrameLayout implements View.OnClickListener {
private CircleView mCvCircle;
private ImageView mIvStar;
private DotsView mDvDots;
private DecelerateInterpolator mDecelerateInterpolator;
private OvershootInterpolator mOvershootInterpolator;
private AccelerateDecelerateInterpolator mAccelerateDecelerateInterpolator;
private AnimatorSet mAnimatorSet;
private boolean mIsChecked = false;
private OnLikeClickListener listener;
public LikeButtonView(Context context) {
super(context);
init();
}
public LikeButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public void setOnLikeCLickListener(OnLikeClickListener listener) {
this.listener = listener;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mCvCircle = (CircleView) findViewById(R.id.like_button_cv_circle);
mIvStar = (ImageView) findViewById(R.id.like_button_iv_star);
mDvDots = (DotsView) findViewById(R.id.like_button_dv_dots);
}
private void init() {
//不懂;
isInEditMode();
LayoutInflater.from(getContext()).inflate(R.layout.like_button_group, this, true);
mDecelerateInterpolator = new DecelerateInterpolator();
mOvershootInterpolator = new OvershootInterpolator(4);
mAccelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator();
setOnClickListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
/** * 按下的时候,星星变小,记录状态为“按着” */
case MotionEvent.ACTION_DOWN:
mIvStar.animate().scaleX(0.7f).scaleY(0.7f).setDuration(150).setInterpolator(mOvershootInterpolator);
// Pass true to set the View's internal state to "pressed",
// or false to reverts the View's internal state from a previously set "pressed" state.
setPressed(true);
break;
/** * 如果状态为“按着”和“手指在本控件内移动”,那就不管。 * 否则,把状态设为“没按着” */
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
boolean isInside = (x > 0 && x < getWidth() && y > 0 && y < getHeight());
// isPressed() : true if the view is currently pressed, false otherwise
if (isPressed() != isInside) {
setPressed(isInside);
}
break;
/** * 手指松开时,星星回复形状, * 如果状态为“按着”的话,那就播放动画。 * 然后把状态设回“没按着”。 */
case MotionEvent.ACTION_UP:
mIvStar.animate().scaleX(1).scaleY(1).setInterpolator(mOvershootInterpolator);
if (isPressed()) {
// Call this view's OnClickListener, if it is defined.
performClick();
setPressed(false);
}
break;
}
return true;
}
@Override
public void onClick(View v) {
// mIsChecked 用来记录黄星还是暗星。true:黄星。false:暗星。
mIsChecked = !mIsChecked;
mIvStar.setImageResource(mIsChecked ? R.drawable.ic_star_rate_on : R.drawable.ic_star_rate_off);
//比如快速的2次点击,当第一次的动画还没结束的时候,第二次点击会把第一次的动画取消。
if (mAnimatorSet != null) {
mAnimatorSet.cancel();
}
if (mIsChecked) {
/** * 动画开始前,把星星和圆点都设置为最小。 */
mIvStar.animate().cancel();
mIvStar.setScaleX(0);
mIvStar.setScaleY(0);
mCvCircle.setInnerCircleRadiusProgress(0);
mCvCircle.setOuterCircleRadiusProgress(0);
mDvDots.setCurrentProgress(0);
mAnimatorSet = new AnimatorSet();
/** * CircleView * * 这是一个圆环,动画开始后, * 圆环的半径越来越大,圆环的环宽越来越窄,颜色由红色变为黄色。 */
ObjectAnimator outerCircleAnimator =
ObjectAnimator.ofFloat(mCvCircle, CircleView.OUTER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
outerCircleAnimator.setDuration(250);
// outerCircleAnimator.setDuration(1250);
outerCircleAnimator.setInterpolator(mDecelerateInterpolator);
ObjectAnimator innerCircleAnimator
= ObjectAnimator.ofFloat(mCvCircle, CircleView.INNER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
innerCircleAnimator.setDuration(200);
// innerCircleAnimator.setDuration(1200);
innerCircleAnimator.setStartDelay(200);
innerCircleAnimator.setInterpolator(mDecelerateInterpolator);
/** * mIvStar */
ObjectAnimator starScaleYAnimator = ObjectAnimator.ofFloat(mIvStar, ImageView.SCALE_Y, 0.2f, 1f);
starScaleYAnimator.setDuration(350);
starScaleYAnimator.setStartDelay(250);
starScaleYAnimator.setInterpolator(mOvershootInterpolator);
ObjectAnimator starScaleXAnimator = ObjectAnimator.ofFloat(mIvStar, ImageView.SCALE_X, 0.2f, 1f);
starScaleXAnimator.setDuration(350);
starScaleXAnimator.setStartDelay(250);
starScaleXAnimator.setInterpolator(mOvershootInterpolator);
/** * DotsView */
ObjectAnimator dotsAnimator = ObjectAnimator.ofFloat(mDvDots, DotsView.DOTS_PROGRESS, 0, 1f);
// dotsAnimator.setDuration(2900);
dotsAnimator.setDuration(900);
dotsAnimator.setStartDelay(50);
// dotsAnimator.setInterpolator(new LinearInterpolator()); //用【LinearInterpolator】就没有弹射的效果。
dotsAnimator.setInterpolator(mAccelerateDecelerateInterpolator);
mAnimatorSet.playTogether(
outerCircleAnimator,
innerCircleAnimator,
starScaleYAnimator,
starScaleXAnimator,
dotsAnimator
);
/** * 比如快速的2次点击,当第一次的动画还没结束的时候,第二次点击会把第一次的动画取消。 * 取消了之后,设置各个控件的状态。 * * addListener(AnimatorListener listener) * public static interface AnimatorListener * public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener * AnimatorListenerAdapter 重写了 AnimatorListener 的所有方法。 * AnimatorListenerAdapter 中的都不是抽象方法,所以只选需要的方法来重写就ok。 */
mAnimatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
mIvStar.setScaleX(1);
mIvStar.setScaleY(1);
mCvCircle.setOuterCircleRadiusProgress(0);
mCvCircle.setInnerCircleRadiusProgress(0);
mDvDots.setCurrentProgress(0);
}
});
mAnimatorSet.start();
listener.onYellowStar();
} else {
listener.onGreyStar();
}
}
}
-End-