android 画一个渐变的圆环

自定义View画一个类似下图的圆环:

分为三步:画底部圆,上层圆,还有文字

其中上层圆需要渐变颜色,并且和数字代表的程度统一。

代码如下:

public class ScoreCircle extends View {
    private static final String TAG = "ScoreCircleLog";
    private int circleRadius;//圆半径
    private int circleStroke;//线宽
    private int totalSize;//View总大小
    private int padding;

    private int firstCircleColor;
    private int secondStartColor;
    private int secondEndColor;
    private SweepGradient mGradient;
    private Matrix gradientMatrix;

    private int frontColor;
    private int frontSize;

    private int totalAngle = 349;//最多只能转350度,不然会重合

    private float totalScore = 100f; //总分100
    private float currentScore = 60f;//
    private DecimalFormat decimalFormat=new DecimalFormat(".0");

    private Paint mPaint;

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

    public ScoreCircle(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ScoreCircle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(attrs,context);
        initPaint();
    }

    private void initAttrs(AttributeSet attrs,Context context) {

        TypedArray typedArray = this.getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ScoreCircle, 0, 0);

        try {
            int width = typedArray.getLayoutDimension(R.styleable.ScoreCircle_android_layout_width, (int) this.getResources().getDimension(R.dimen.scoreCircle_size));
            int height = typedArray.getLayoutDimension(R.styleable.ScoreCircle_android_layout_height, (int)this.getResources().getDimension(R.dimen.scoreCircle_size));
            setTotalSize(width,height);
            padding = (int) typedArray.getDimension(R.styleable.ScoreCircle_padding, this.getResources().getDimension(R.dimen.scoreCircle_padding));
            circleStroke = (int) typedArray.getDimension(R.styleable.ScoreCircle_stroke, this.getResources().getDimension(R.dimen.scoreCircle_stroke));
            firstCircleColor = typedArray.getColor(R.styleable.ScoreCircle_firstCircleColor,ContextCompat.getColor(context,R.color.ScoreCircle_first_color));
            secondStartColor = typedArray.getColor(R.styleable.ScoreCircle_sendColorStart,ContextCompat.getColor(context,R.color.ScoreCircle_second_start));
            secondEndColor = typedArray.getColor(R.styleable.ScoreCircle_sendColorEnd,ContextCompat.getColor(context,R.color.ScoreCircle_second_end));
            frontColor = typedArray.getColor(R.styleable.ScoreCircle_front_color,ContextCompat.getColor(context,R.color.ScoreCircle_front_color));
            frontSize = (int) typedArray.getDimension(R.styleable.ScoreCircle_front_size,AppUtils.dpToPx(context,22));

        } finally {
            typedArray.recycle();
        }

    }

    public void setScore(float score) {
        if (score > 100)
            score = 100;
        if (score < 0)
            score = 0;

        this.currentScore = score;
        invalidate();
    }

    private void setTotalSize(int width,int height){
        if (width == WRAP_CONTENT || width == MATCH_PARENT){
            if (width == WRAP_CONTENT){
                totalSize = (int)this.getResources().getDimension(R.dimen.scoreCircle_size);
            }
        }else {
            if (width > height){
                totalSize = width;
            }else
                totalSize = height;
        }
    }

    private void initPaint(){
        mPaint = new Paint();
        mGradient = new SweepGradient(0,0,secondStartColor,secondEndColor);
        gradientMatrix = new Matrix();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       totalSize = resolveSize(totalSize,widthMeasureSpec);
       circleRadius = totalSize/2 - padding - circleStroke/2;
       setMeasuredDimension(totalSize,totalSize);
    }

  //  invalidate();  ondraw
  //  requestLayout(); onMeasure onlayout

    @Override
    protected void onDraw(Canvas canvas) {
        drawFirstCircle(canvas);
        drawSecondCircle(canvas);
        drawText(canvas);
    }
    //底部圆
    private void drawFirstCircle(Canvas canvas) {
        mPaint.reset();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(circleStroke);
        mPaint.setColor(firstCircleColor);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(totalSize/2,totalSize/2,circleRadius,mPaint);
    }
    //表层圆
    @SuppressLint("NewApi")
    private void drawSecondCircle(Canvas canvas) {
        mPaint.reset();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(circleStroke+2);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setShader(mGradient);

        float angle = (currentScore / totalScore)*totalAngle;
        canvas.save();

        gradientMatrix.setTranslate(totalSize/2,totalSize/2);
        mGradient.setLocalMatrix(gradientMatrix);
        // gradientMatrix.setRotate(0.9f,totalSize/2,totalSize/2);
        canvas.rotate(-90,totalSize/2,totalSize/2);
        //  mGradient.setLocalMatrix(gradientMatrix);

        canvas.drawArc(padding+circleStroke/2, padding+circleStroke/2 ,
                totalSize - padding-circleStroke/2, totalSize - padding-circleStroke/2,
                6,angle,false,mPaint
        );

        canvas.restore();
    }
    //中间文字
    private void drawText(Canvas canvas) {
        mPaint.reset();
        mPaint.setAntiAlias(true);
        mPaint.setFakeBoldText(true);
        Rect textBounds = new Rect();
        String score = decimalFormat.format(currentScore);
        mPaint.setTextSize(frontSize);
        frontColor = ContextCompat.getColor(getContext(),R.color.ScoreCircle_front_color);
        mPaint.setColor(frontColor);
        mPaint.getTextBounds(score,0,score.length(),textBounds);
        canvas.drawText(score,totalSize/2 - textBounds.width()/2 - textBounds.left,
                totalSize/2 + textBounds.height()/2 - textBounds.bottom  ,mPaint);
    }

这样就可以画出来,但是还有zu最后一部,保存画过的状态,

 @Nullable
    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable parcelable = super.onSaveInstanceState();
        SavedState savedState = new SavedState(parcelable);

        savedState.SavedCurrentScore = currentScore;

        return savedState;
    }

    private static class SavedState extends BaseSavedState{

        float SavedCurrentScore;

        public SavedState(Parcel source) {
            super(source);
            SavedCurrentScore = source.readFloat();
        }

        public SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeFloat(SavedCurrentScore);
        }

        public static final Creator<SavedState> CREATOR = new Creator<SavedState>(){

            @Override
            public SavedState createFromParcel(Parcel source) {
                return new SavedState(source);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

}

这样View重绘的时候状态不会变掉。

猜你喜欢

转载自blog.csdn.net/crookshanks_/article/details/83475228