@作者 : 西野奈留
@博客:http://blog.youkuaiyun.com/narunishino
-2016/4/11-
项目来自这位大神:
http://blog.youkuaiyun.com/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-