Android_实现星星控件_学习

@作者 : 西野奈留
@博客:http://blog.csdn.net/narunishino
-2016/4/11-

Android_实现星星控件_学习_第1张图片

项目来自这位大神:

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-

你可能感兴趣的:(android,view,自定义,控件,星星)