Android 转俩圈打对勾

失败作品

public class CircleView extends View {

    boolean isEnd = false;

    private Path mPath;
    private Paint mPaint;
    private PathMeasure mPathMeasure;
    private float mAnimatorValue;
    private Path mDst;
    private float mLength;
    private Path mDuihaoPath;
    private int width;

    private Bitmap bitmapCanvas;
    private Canvas canvas2;
    private Paint mDuihaoPaint;

    public CircleView(Context context) {
        super(context);
    }

    public CircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPathMeasure = new PathMeasure();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(6);
        mPaint.setTextSize(60);

//        mPaint.setStrokeCap(Paint.Cap.BUTT);
        //圆形的时候 有明显的圆形 开头/结尾
        mPaint.setStrokeCap(Paint.Cap.ROUND);
//        mPaint.setStrokeCap(Paint.Cap.SQUARE);

//        mPaint.setStrokeJoin(Paint.Join.BEVEL);
//        mPaint.setStrokeJoin(Paint.Join.MITER);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPath = new Path();


        //200  200  这个点 就是这个圆形 中心坐标  这个坐标是相对于 View在XML 里的左上角的点为0 0
//        mPath.addCircle(200, 200, 100, Path.Direction.CW);

        width = ConvertUtils.dp2px(300);

        mPath.addCircle(width / 2, width / 2, width / 2, Path.Direction.CW);// 顺时针转

        // forceClosed  Path最终是否需要闭合,如果为True的话,
        //                          则不管关联的Path是否是闭合的,都会被闭合。
        mPathMeasure.setPath(mPath, true);
        mLength = mPathMeasure.getLength();
        mDst = new Path();

        final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mAnimatorValue = (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });

        valueAnimator.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                isEnd = true;


                final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        mAnimatorValue = (float) valueAnimator.getAnimatedValue();
                        invalidate();
                    }
                });
                valueAnimator.start();


                mDuihaoPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
                mDuihaoPaint.setStyle(Paint.Style.STROKE);
                mDuihaoPaint.setStrokeWidth(6);
                mDuihaoPaint.setTextSize(60);
                bitmapCanvas = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
                canvas2 = new Canvas(bitmapCanvas);
                mDuihaoPath = new Path();

                mDuihaoPath.moveTo(width * 0.2f, width * 0.5f);
                mDuihaoPath.quadTo(width / 2f, width, width * 0.8f, width * 0.3f);

                PathMeasure mPathMeasure = new PathMeasure(mDuihaoPath, false);
                final float length = mPathMeasure.getLength();

                ValueAnimator mAnimator = ValueAnimator.ofFloat(1, 0);
                mAnimator.setInterpolator(new LinearInterpolator());
                mAnimator.setDuration(2000);
                mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float fraction = (float) animation.getAnimatedValue();
                        DashPathEffect mEffect = new DashPathEffect(new float[]{length, length}, fraction * length);
                        mDuihaoPaint.setPathEffect(mEffect);
                        invalidate();
                    }
                });
                mAnimator.start();

            }
        });

        valueAnimator.setDuration(1000);
        valueAnimator.setRepeatCount(2);
        valueAnimator.start();


    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mDst.reset();
        // 硬件加速的BUG  加上这个会在左上角留下一个黑点
//        mDst.lineTo(0, 0);

        float stop = mLength * mAnimatorValue;


        if (isEnd) {
            float start = (float) (stop - ((1 - Math.abs(mAnimatorValue - 1)) * mLength));
            mPathMeasure.getSegment(start, stop, mDst, true);
            canvas.drawPath(mDst, mPaint);
        } else {
            float start = (float) (stop - ((0.7 - Math.abs(mAnimatorValue - 0.7)) * mLength));
            mPathMeasure.getSegment(start, stop, mDst, true);
            canvas.drawPath(mDst, mPaint);
        }

        if(canvas2 != null){
            canvas2.drawPath(mDuihaoPath, mDuihaoPaint);
            canvas.drawBitmap(bitmapCanvas, 0,0,mDuihaoPaint);
        }


    }
}

 


 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MdStyleProgress">
        <attr name="progress_color" format="color"/>
        <attr name="progress_width" format="dimension"/>
        <attr name="radius" format="dimension"/>
    </declare-styleable>
</resources>
package com.as.demo_ok75;

import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

public class MdStyleProgress extends View {

    private static final int PROGRESS_COLOR = Color.parseColor("#10a679");
    private static final int PROGRESS_WIDTH = 3;
    private static final int RADIUS = 30;

    private int mProgressColor = PROGRESS_COLOR;
    private int mProgressWidth = dp2px(PROGRESS_WIDTH);
    private int mRadius = dp2px(RADIUS);

    private Paint progressPaint;

    private int rotateDelta = 4;
    private int curAngle = 0;

    private int minAngle = -90;
    private int startAngle = -90;
    private int endAngle = 120;

    private Path path;
    private Status mStatus = Status.Loading;
    private float lineValueLeft;//左边对勾
    private float lineValueRight;//右边对勾
    private float failLineFirst;//叉号
    private float failLineSecond;

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

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

    public MdStyleProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取自定义属性
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MdStyleProgress);
        int indexCount = typedArray.getIndexCount();
        for (int i=0;i<indexCount;i++){
            int attr = typedArray.getIndex(i);
            switch (attr){
                case R.styleable.MdStyleProgress_progress_color:
                    mProgressColor = typedArray.getColor(attr,PROGRESS_COLOR);
                    break;
                case R.styleable.MdStyleProgress_progress_width:
                    mProgressWidth = (int) typedArray.getDimension(attr,mProgressWidth);
                    break;
                case R.styleable.MdStyleProgress_radius:
                    mRadius = (int) typedArray.getDimension(attr,mRadius);
                    break;
            }
        }
        //回收TypedArray对象
        typedArray.recycle();
        //设置画笔
        setPaint();

        path = new Path();
        path.moveTo(mRadius/2,mRadius);
        path.lineTo(mRadius,mRadius+mRadius/2);
        path.lineTo(mRadius+mRadius/2,mRadius/2);
    }

    private void setPaint() {
        progressPaint = new Paint();
        progressPaint.setAntiAlias(true);
        progressPaint.setDither(true);
        progressPaint.setColor(mProgressColor);
        progressPaint.setStyle(Paint.Style.STROKE);
        progressPaint.setStrokeWidth(mProgressWidth);
        progressPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSize;
        int heightSize;
        if(widthMode != MeasureSpec.EXACTLY){
            widthSize = getPaddingLeft() + mProgressWidth + mRadius*2 + getPaddingRight();
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize,MeasureSpec.EXACTLY);
        }
        if(heightMode != MeasureSpec.EXACTLY){
            heightSize = getPaddingTop() + mProgressWidth + mRadius*2 + getPaddingBottom();
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize,MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        canvas.translate(getPaddingLeft(),getPaddingTop());

        if(mStatus == Status.Loading){
            if (startAngle == minAngle) {
                endAngle += 6;
            }
            if (endAngle >= 300 || startAngle > minAngle) {
                startAngle += 6;
                if(endAngle > 20) {
                    endAngle -= 6;
                }
            }
            if (startAngle > minAngle + 300) {
                minAngle = startAngle;
                endAngle = 20;
            }
            canvas.rotate(curAngle += rotateDelta,mRadius,mRadius);//旋转rotateDelta=4的弧长
            canvas.drawArc(new RectF(0,0,mRadius*2,mRadius*2),startAngle,endAngle,false,progressPaint);
            invalidate();
        }else if(mStatus == Status.LoadSuccess){
            canvas.drawArc(new RectF(0,0,mRadius*2,mRadius*2),startAngle,360,false,progressPaint);
            //canvas.drawPath(path,progressPaint);
            //画圆圈中的对勾
            canvas.drawLine(mRadius/2,mRadius,mRadius/2+lineValueLeft,mRadius+lineValueLeft,progressPaint);
            canvas.drawLine(mRadius,mRadius+mRadius/2,mRadius+lineValueRight,mRadius+mRadius/2-1.5f*lineValueRight,progressPaint);
        }else {
            canvas.drawArc(new RectF(0,0,mRadius*2,mRadius*2),startAngle,360,false,progressPaint);
            //画圆圈中的叉号(画右边叉号的时候,终止位置的x坐标为起始x位置减去failLineFirst,而failLineFirst在属性动画中的取值范围是0-mRadius)
            canvas.drawLine(mRadius+mRadius/2,mRadius/2,mRadius*3/2-failLineFirst,mRadius/2+failLineFirst,progressPaint);
            canvas.drawLine(mRadius/2,mRadius/2,mRadius/2+failLineSecond,mRadius/2+failLineSecond,progressPaint);
        }

        canvas.restore();
    }


    public enum Status{
        Loading,
        LoadSuccess,
        LoadFail
    }

    public void startAnima(){
        //对勾左边线的属性动画
        ValueAnimator animatorLeft = ValueAnimator.ofFloat(0f,mRadius/2f);
        animatorLeft.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
               lineValueLeft = (float) animation.getAnimatedValue();
                Log.i("lineValueLeft",lineValueLeft+"");
                invalidate();//重绘,调onDraw()重绘
            }
        });
        //对勾右边线的属性动画
        ValueAnimator animatorRight = ValueAnimator.ofFloat(0f,mRadius/2f);
        animatorRight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                lineValueRight = (float) animation.getAnimatedValue();
                Log.i("lineValueRight",lineValueRight+"");
                invalidate();
            }
        });
        //将多个动画组合到一起需要借助AnimatorSet这个类
        final AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animatorRight).after(animatorLeft);
        animatorSet.setDuration(150);
        animatorSet.start();
    }

    public void failAnima(){
        ValueAnimator failOne = ValueAnimator.ofFloat(0f,mRadius);
        failOne.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                failLineFirst = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        ValueAnimator failOther = ValueAnimator.ofFloat(0f,mRadius);
        failOther.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                failLineSecond = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(failOther).after(failOne);
        animatorSet.setDuration(150);
        animatorSet.start();
    }

    public Status getStatus() {
        return mStatus;
    }

    public void setStatus(Status mStatus) {
        this.mStatus = mStatus;
        invalidate();
    }

    /**
     * dp 2 px
     */
    protected int dp2px(int dpVal)
    {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, getResources().getDisplayMetrics());
    }
    /**
     * sp 2 px
     */
    protected int sp2px(int spVal)
    {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                spVal, getResources().getDisplayMetrics());
    }
}
<com.as.demo_ok75.MdStyleProgress
        android:id="@+id/msp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:progress_color="@color/colorPrimary"
        app:progress_width="2dp"
        app:radius="40dp" />
public class MainActivity extends AppCompatActivity {



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final MdStyleProgress msp = findViewById(R.id.msp);
        ThreadUtils.executeBySingle(new ThreadUtils.SimpleTask<Object>() {
            @Override
            public Object doInBackground() throws Throwable {
                Thread.sleep(5000);
                return null;
            }

            @Override
            public void onSuccess(Object result) {
                msp.setStatus(MdStyleProgress.Status.LoadFail);
                msp.failAnima();


//                msp.setStatus(MdStyleProgress.Status.LoadSuccess);
//                msp.startAnima();
            }
        });

    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值