自定义实现圆环进度条

一.效果图

 自定义实现圆环进度条_第1张图片


二.实现原理

  1.先绘制背景圆环和代表进度的圆环。

  2.绘制两端的小圆

  3.使用SweepGradient为圆环添加渐变色

  4.绘制阴影

   5.绘制中间文字

三.实现的具体过程

  1.自定义View的基本过程,自定义属性和获取自定义属性

 <declare-styleable name="ProgressBarView">

        <attr name="progressbar_color_start" format="color">attr> //圆弧的颜色
        <attr name="progressbar_color_end" format="color">attr>
        <attr name="progressbar_shadow_color" format="color">attr>  //阴影的颜色
        <attr name="progressbar_end_color" format="color">attr> //圆弧结束时候的颜色
        <attr name="progressbar_start_color" format="color">attr> //圆弧起始时候的颜色
        <attr name="progressbar_default_color" format="color">attr> //圆弧默认的颜色
        <attr name="progressbar_inside_circle_radius" format="dimension"/> //内部圆的半径
        <attr name="progressbar_outside_circle_radius" format="dimension"/> //外部圆的半径
        <attr name="progressbar_circle_width" format="dimension"/>   //默认圆弧和其他圆弧之间的距离
        <attr name="progressbar_progress" format="integer"/> //进度条的大小
    declare-styleable>
  TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressBarView);

        startColor =typedArray.getColor(R.styleable.ProgressBarView_progressbar_start_color, Color.BLACK);
        endColor=typedArray.getColor(R.styleable.ProgressBarView_progressbar_end_color,Color.WHITE);
        defaultColor=typedArray.getColor(R.styleable.ProgressBarView_progressbar_default_color,Color.WHITE);
        startColor=typedArray.getColor(R.styleable.ProgressBarView_progressbar_color_start,Color.WHITE);
        endColor = typedArray.getColor(R.styleable.ProgressBarView_progressbar_color_end,Color.WHITE);
        shadowColor = typedArray.getColor(R.styleable.ProgressBarView_progressbar_shadow_color,Color.WHITE);
        insideCircleRadius=typedArray.getDimension(R.styleable.ProgressBarView_progressbar_inside_circle_radius,50);
        outsideCircleRadius=typedArray.getDimension(R.styleable.ProgressBarView_progressbar_outside_circle_radius,50);
        circleWidth = typedArray.getDimension(R.styleable.ProgressBarView_progressbar_circle_width,40);
        progress = typedArray.getInteger(R.styleable.ProgressBarView_progressbar_progress,350);

绘制圆环的方法主要有两种,一种是通过绘制两个圆,在使用Paint.setXferMode()的方法来绘制,还有一种就是通过绘制Path来绘制圆环。

  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void drawDefaultCircularArc(Canvas canvas){
        defaultCirclePaint.reset();
        defaultCirclePaint.setColor(Color.WHITE);
        int sc=canvas.saveLayer(new RectF(centerX-outsideCircleRadius,centerY-outsideCircleRadius,centerX+outsideCircleRadius,centerY+outsideCircleRadius), defaultCirclePaint);
        canvas.drawCircle(centerX,centerY,insideCircleRadius, defaultCirclePaint);
        defaultCirclePaint.setColor(defaultColor);
        defaultCirclePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        canvas.drawCircle(centerX,centerY,outsideCircleRadius, defaultCirclePaint);
        canvas.restoreToCount(sc);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void drawTypeCircularArc(Canvas canvas){
        circlePaint.setShader(sweepGradient);
        RectF outRectF = new RectF(centerX-outsideCircleRadius-circleWidth,centerY-outsideCircleRadius-circleWidth,
                centerX+outsideCircleRadius+circleWidth,centerY+outsideCircleRadius+circleWidth);
        RectF insideRectF = new RectF(centerX-insideCircleRadius+circleWidth,centerY-insideCircleRadius+circleWidth,
                centerX+insideCircleRadius-circleWidth,centerY+insideCircleRadius-circleWidth);
        int sc=canvas.saveLayer(outRectF,circlePaint);
        canvas.translate(centerX,centerY);
        canvas.rotate(-90);
        canvas.translate(-centerX,-centerY);
        canvas.drawArc(insideRectF,startAngle,progress,true,circlePaint);
        circlePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        canvas.drawArc(outRectF,startAngle,progress, true,circlePaint);
        circlePaint.setAlpha(0);
        canvas.drawCircle(centerX,centerY,insideCircleRadius-circleWidth,circlePaint);
        canvas.restoreToCount(sc);
        circlePaint.reset();

这里使用的是Paint.setXferMode()的方法,该Mode总共有16种模式。绘制两端的小圆

 private void drawSemicircle(Canvas canvas,int startAngle,boolean isClockwise){
        canvas.save();
        canvas.translate(centerX,centerY);
        canvas.rotate(-90);
        canvas.translate(-centerX,-centerY);
        int sweepAngle= isClockwise? 180:-180;
        startAngle = isClockwise? startAngle-1:startAngle+1;
        double anglePi = Math.toRadians(startAngle);
        float radius = insideCircleRadius+(outsideCircleRadius-insideCircleRadius)/2;
        float circleRadius = radius-insideCircleRadius+circleWidth;
        float circleCenterY= (float) (Math.sin(anglePi)*radius+centerY);
        float circleCenterX = (float) (Math.cos(anglePi)*radius+centerX);
        RectF rectF = new RectF(circleCenterX-circleRadius,circleCenterY-circleRadius,
                circleCenterX+circleRadius,circleCenterY+circleRadius);
        if(!isClockwise){
            shadowDrawable.setCircleRectFFirst(rectF);
            shadowDrawable.setY((float) (Math.sin(anglePi)*insideCircleRadius+centerY));
            shadowDrawable.setX((float) (Math.cos(anglePi)*insideCircleRadius+centerX));
        }else{
            shadowDrawable.setCircleRectFLast(rectF);
        }
        canvas.drawArc(rectF,startAngle,sweepAngle,true,circlePaint);
        canvas.restore();
    }

使用SweepGradient为圆环添加渐变色,就设置Paint.setShadow()就好了

if(progress!=360){
            startAngle+=10;
            progress-=10;
            sweepGradient = new SweepGradient(centerX,centerY,new int[]{startColor,endColor},new float[]{0,progress/360f});
        }else{
            sweepGradient = new SweepGradient(centerX,centerY,new int[]{startColor,endColor,startColor},new float[]{0,0.8f,1f});
        }

在添加进度条的阴影效果,普遍添加阴影效果的方法就有三种,

1. .9图的设置 

2.自定义xml,通过不断的叠加 

3.使用elevation来设置阴影效果

但在这里这些方法都不行,因为该阴影要根据进度条的变化而变化,而上面这些阴影设置都不能在进行改变。

所以这里使用的方法是 写一个继承于Drawable的类,通过Paint.setShadowLayer()来实现阴影效果

public ShadowDrawable(int shadowColor, int shadowRadius, int offsetX, int offsetY,int startAngle) {
		this.mOffsetX = offsetX;
		this.mOffsetY = offsetY;
		this.mStartAngle = startAngle;
		mShadowPaint = new Paint();
		mShadowPaint.setColor(Color.TRANSPARENT);
		mShadowPaint.setAntiAlias(true);
		mShadowPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
		mShadowPaint.setShadowLayer(shadowRadius, offsetX, offsetY, shadowColor);
		mPath = new Path();
	}


	@Override
	public void draw(@NonNull Canvas canvas) {
		canvas.save();
		canvas.translate(mInsideRectF.centerX(),mInsideRectF.centerY());
		canvas.rotate(-90);
		canvas.translate(-mInsideRectF.centerX(),-mInsideRectF.centerY());
		mPath.reset();
		if(mProgress!=360){
			mShadowPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
			mPath.moveTo(x,y);
			mPath.arcTo(mCircleRectFFirst,mStartAngle,-180);
			mPath.arcTo(mOutsideRectF,mStartAngle,mProgress);
			mPath.arcTo(mCircleRectFLast,mStartAngle+mProgress,180);
			mPath.arcTo(mInsideRectF,mStartAngle+mProgress,-1*mProgress);
			canvas.drawPath(mPath,mShadowPaint);
		}else{
			canvas.drawCircle(mOutsideRectF.centerX(),mOutsideRectF.centerY(),mOutsideRectF.centerX()-mOutsideRectF.left,mShadowPaint);
			canvas.drawCircle(mInsideRectF.centerX(),mInsideRectF.centerY(),mInsideRectF.centerX()-mInsideRectF.left,mShadowPaint);
		}
		canvas.restore();
	}
public static void setShadowDrawable(View view, Drawable drawable) {
		view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);  //关闭当前View的硬件加速
		ViewCompat.setBackground(view, drawable);
	}

阴影这里绘制的效果就是使用Path来绘制圆环的。这样之后,只需要在自定义进度条调用setShadowDrawable()方法就好了

最后一步绘制中间的文字,这里主要的就是如何让文字居中绘制

 private void drawText(Canvas canvas,String text){
        Paint textPaint = new Paint();
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setColor(Color.BLACK);
        textPaint.setTextSize(50);
        Paint.FontMetrics fp = textPaint.getFontMetrics();
        float length = textPaint.measureText(text);
        canvas.drawText(text,centerX-length/2,centerY-fp.top/2-fp.bottom/2,textPaint);
    }

最后效果就实现了

转载于:https://www.cnblogs.com/xiongbo753/p/10058431.html

你可能感兴趣的:(自定义实现圆环进度条)