用屬性動畫實現一個確認按鈕

weixin_34050427發表於2017-06-17

不多BB,先上圖


3515789-7287e54c3cebfa82.gif
  • 此按鈕由一個圓一個勾組成,準確的說應該是一個圓2條線組成
  • 還有動畫,這裡用的是屬性動畫,分為4部分,圓圈,線(2條),還有整體的放大縮小

開工

這裡不解釋初始化畫筆,各種資料過程,

關鍵點在onDraw方法裡

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        Log.e("current", "X:" + mCenterX + "," + "Y:" + mCenterY);
        mRectF.left = mCenterX - mRadius;
        mRectF.top = mCenterY - mRadius;
        mRectF.right = mCenterX + mRadius;
        mRectF.bottom = mCenterY + mRadius;
        //畫圓
        canvas.drawArc(mRectF, 0, mDegree, false, mCirclePaint);
        //畫勾左邊
        canvas.drawLine(mCenterX - mRadius / 2, mCenterY,
                mCenterX - mRadius / 2 + mLeftValue, mCenterY + mLeftValue,
                mLinePaint);
        //畫勾的右邊
        //mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue這個座標在下圖解析
        canvas.drawLine(mCenterX, mCenterY + mRadius / 2,
                mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue, mLinePaint);
    }

mLeftValue,mRightValue是動態改變的

下面解釋mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue這個座標

3515789-780cf02348769983.png

這裡m=mRightValue(動態變化的值)
h就是勾右邊線座標高度
1.7是估計出來的值,假設勾右邊線與y軸成30度

其他的比如動畫等的,原始碼裡註釋的很清楚-----AnimationViewSet

原始碼

/**
     * 圓圈的畫筆
     */
    private Paint mCirclePaint;
    /**
     * 線的畫筆
     */
    private Paint mLinePaint;
    /**
     * 設定線寬,px
     */
    private float mStrokeWidth = 10;

    private float mCenterX, mCenterY;

    /**
     * 為了畫出目標圓形的矩形外框
     */
    private RectF mRectF = new RectF();

    /**
     * 圓的半徑
     */
    private float mRadius = 300;

    /**
     * 畫圓時動態設定的角度
     */
    private Float mDegree = 360f;

    private Float mLeftValue = 150f;
    private Float mRightValue = 150f;
    //預設半徑
    private static final int DEFAULT_RADIUS = 150;
    //邊距
    private static final float PADDING = 20;

    private AnimatorSet mAnimatorSet = new AnimatorSet();
    private ValueAnimator mCircleAnim;
    private ValueAnimator mLineLeftAnimator;
    private ValueAnimator mLineRightAnimator;


    public ConfirmView(Context context) {
        this(context, null);
    }

    public ConfirmView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ConfirmView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    /**
     * 初始化畫筆
     */
    private void initPaint() {
        mCirclePaint = new Paint();
        //抗鋸齒
        mCirclePaint.setAntiAlias(true);
        //設定連線點為圓角
        mCirclePaint.setStrokeJoin(Paint.Join.ROUND);
        mCirclePaint.setStrokeWidth(mStrokeWidth);
        mCirclePaint.setColor(Color.WHITE);
        mCirclePaint.setStyle(Paint.Style.STROKE);


        mLinePaint = new Paint();
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStrokeJoin(Paint.Join.ROUND);
        mLinePaint.setStrokeWidth(mStrokeWidth);
        mLinePaint.setColor(Color.WHITE);
        mLinePaint.setStyle(Paint.Style.STROKE);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        reMeasure();
    }

    /**
     * 重新測量寬和高
     */
    private void reMeasure() {
        int viewWidth = getMeasuredWidth();
        int viewHeight = getMeasuredHeight();
        mCenterX = viewWidth / 2;
        mCenterY = viewHeight / 2;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w / 2;
        mCenterY = h / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        Log.e("current", "X:" + mCenterX + "," + "Y:" + mCenterY);
        mRectF.left = mCenterX - mRadius;
        mRectF.top = mCenterY - mRadius;
        mRectF.right = mCenterX + mRadius;
        mRectF.bottom = mCenterY + mRadius;
        //畫圓
        canvas.drawArc(mRectF, 0, mDegree, false, mCirclePaint);
        //畫勾左邊
        canvas.drawLine(mCenterX - mRadius / 2, mCenterY,
                mCenterX - mRadius / 2 + mLeftValue, mCenterY + mLeftValue,
                mLinePaint);
        //畫勾的右邊
        //mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue這個座標
        canvas.drawLine(mCenterX, mCenterY + mRadius / 2,
                mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue, mLinePaint);
    }

    public void loadCircle(int mRadius) {
        mRadius = mRadius < 0 ? DEFAULT_RADIUS : mRadius;
        this.mRadius = mRadius - PADDING;
        if (mAnimatorSet != null && mAnimatorSet.isRunning()) {
            return;
        }
        resetDegreeAndLeftRightValueAndPaintColor();
        reMeasure();

        //這裡其實限定了
        //mDegree,對應更新值的方法是mLeftValue = (Float) animation.getAnimatedValue();,在下面的監聽器裡
        //mLeftValue
        //mRightValue三個數的取值
        mCircleAnim = ValueAnimator.ofFloat(0, 360);
        mLineLeftAnimator = ValueAnimator.ofFloat(0, this.mRadius / 2f);
        mLineRightAnimator = ValueAnimator.ofFloat(0, this.mRadius / 2f);

        mCircleAnim.setDuration(800);
        mLineLeftAnimator.setDuration(500);
        mLineRightAnimator.setDuration(500);

        mCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mDegree = (Float) animation.getAnimatedValue();
                invalidate();
            }
        });

        mLineLeftAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mLeftValue = (Float) animation.getAnimatedValue();
                invalidate();
            }
        });

        mLineRightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mRightValue = (Float) animation.getAnimatedValue();
                invalidate();
            }
        });

        mAnimatorSet.play(mCircleAnim).before(mLineLeftAnimator);
        mAnimatorSet.play(mLineRightAnimator).after(mLineLeftAnimator);
        mAnimatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                stopPropertyAnimation();
                if (mEndListener != null) {
                    mEndListener.onCircleDone();
                    //放大效果
                    loadEndAnim();
                }
            }
        });
        mAnimatorSet.start();
    }

    /**
     * 載入結束動畫
     */
    private void loadEndAnim() {
        //放大的值
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(this, "scaleX", 1.0f, 1.2f, 1.0f);
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(this, "scaleY", 1.0f, 1.2f, 1.0f);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(3000);
        set.setInterpolator(new BounceInterpolator());
        set.playTogether(scaleXAnim, scaleYAnim);
        set.start();
    }

    private void stopPropertyAnimation() {
        if (null != mCircleAnim) {
            mCircleAnim.end();
        }
        if (null != mLineLeftAnimator) {
            mLineLeftAnimator.end();
        }
        if (null != mLineRightAnimator) {
            mLineRightAnimator.end();
        }
        clearAnimation();
    }

    private void resetDegreeAndLeftRightValueAndPaintColor() {
        mDegree = 0f;
        mLeftValue = 0f;
        mRightValue = 0f;
        mCirclePaint.setColor(Color.WHITE);
        mLinePaint.setColor(Color.WHITE);
    }


    public interface onCircleFinishListener {
        void onCircleDone();
    }

    private onCircleFinishListener mEndListener;

    public void addCircleAnimatorEndListener(onCircleFinishListener endListener) {
        if (mEndListener == null) {
            this.mEndListener = endListener;
        }
    }

    public void setPaintColor(int color) {
        mCirclePaint.setColor(color);
        mLinePaint.setColor(color);
        invalidate();
    }
}

相關文章