Android自定义圆弧进度条(半圆进度条) 圆弧渐变色进度条带指示 圆弧宽高可自由修改

Posted yeziyfx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义圆弧进度条(半圆进度条) 圆弧渐变色进度条带指示 圆弧宽高可自由修改相关的知识,希望对你有一定的参考价值。

首先我们来看下效果图

圆弧高度可以自定义,说明,只有高度设置为宽度的二分之一时,才是半圆,否则就是半圆的一部分,即圆弧。

不只是圆弧是自定的,图中的文字“2”的控件也是自定义的, 下面也会给出源码。

不多说,直接上源码:

圆弧进度条控件:

/**
 * Created by yfx on 2022/10/11 17:32
 * 
 */
public class CircleBarView extends View 
    private Paint rPaint;//绘制矩形的画笔
    private Paint progressPaint;//绘制圆弧的画笔
    private Paint anchorPaint,anchorBgPaint;//锚点
    private float anchorRadius,anchorBgRadius;
    private int anchorColor,anchorBgColor;
    private CircleBarAnim anim;
    private Paint bgPaint;//绘制背景圆弧的画笔
    private float progress;//可以更新的进度条数值
    private float maxProgress;//进度条最大值
    private float progressSweepAngle;//进度条圆弧扫过的角度
    private int startAngle;//背景圆弧的起始角度
    private float sweepAngle;//背景圆弧扫过的角度
    private RectF mRectF;//绘制圆弧的矩形区域
    private float barWidth;//圆弧进度条宽度
    private int defaultSize;//自定义View默认的宽高
    private int[] progressColors;//进度条圆弧颜色
    private int bgColor;//背景圆弧颜色
    private SweepGradient sweepGradient;//进度条颜色使用渐变色
    private LinearGradient linearGradient;
    private float circleWidth,circleHeight;
    private float xDiff;
    public CircleBarView(Context context, AttributeSet attrs) 
        super(context, attrs);
        init(context,attrs);
    
    private void init(Context context,AttributeSet attrs) 
        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CircleBarView);
        int color1 = typedArray.getColor(R.styleable.CircleBarView_progress_color1,Color.RED);
        int color2 = typedArray.getColor(R.styleable.CircleBarView_progress_color2,color1);
        int color3 = typedArray.getColor(R.styleable.CircleBarView_progress_color3,color2);//写法巧妙
        progressColors=new int[]color1,color1,color2,color3;//必须得4个,
        bgColor = typedArray.getColor(R.styleable.CircleBarView_bg_color,Color.GRAY);//默认为灰色
        circleWidth = typedArray.getDimension(R.styleable.CircleBarView_circle_width,dip2px(context,200));//默认为0
        circleHeight = typedArray.getDimension(R.styleable.CircleBarView_circle_height,dip2px(context,80));//默认为360
        barWidth = typedArray.getDimension(R.styleable.CircleBarView_bar_width,dip2px(context,10));//默认为10dp
        anchorRadius = typedArray.getDimension(R.styleable.CircleBarView_anchor_radius,dip2px(context,5));
        anchorBgRadius = typedArray.getDimension(R.styleable.CircleBarView_anchor_bg_radius,dip2px(context,8.5f));
        anchorColor = typedArray.getColor(R.styleable.CircleBarView_anchor_color,Color.RED);
        anchorBgColor = typedArray.getColor(R.styleable.CircleBarView_anchor_bg_color,Color.GREEN);
        maxProgress = typedArray.getInt(R.styleable.CircleBarView_progress_max,100);
        typedArray.recycle();//typedArray用完之后需要回收,防止内存泄漏

        rPaint=new Paint();
        rPaint.setStyle(Paint.Style.STROKE);//只描边,不填充
        rPaint.setColor(Color.RED);

        progressPaint=new Paint();
        progressPaint.setStyle(Paint.Style.STROKE);//只描边,不填充

        progressPaint.setStrokeWidth(barWidth);
        progressPaint.setAntiAlias(true);//设置抗锯齿
        progressPaint.setStrokeCap(Paint.Cap.ROUND);

        //锚点
        anchorPaint=new Paint();
        anchorPaint.setAntiAlias(true);//设置抗锯齿
        anchorPaint.setColor(anchorColor);
        //锚点背景
        anchorBgPaint=new Paint();
        anchorBgPaint.setAntiAlias(true);//设置抗锯齿

        int a=Color.alpha(anchorBgColor);
        int r=Color.red(anchorBgColor);
        int g=Color.green(anchorBgColor);
        int b=Color.blue(anchorBgColor);
        LogSuperUtil.i("circle_bar","a="+a+",r="+r+",g="+g+",b="+b);
        anchorBgPaint.setColor(Color.rgb(r,g,b));
        anchorBgPaint.setAlpha(a);
        /*raw
        anchorBgPaint.setColor(anchorBgColor);
        anchorBgPaint.setAlpha(185);*/

        anim=new CircleBarAnim();
        bgPaint=new Paint();
        bgPaint.setStyle(Paint.Style.STROKE);
        bgPaint.setColor(bgColor);
        bgPaint.setStrokeWidth(barWidth);
        bgPaint.setAntiAlias(true);
        bgPaint.setStrokeCap(Paint.Cap.ROUND);
        mRectF=new RectF();

        //
        defaultSize=dip2px(context,200);
    
    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);
        //进度条的总轮廓
        canvas.drawArc(mRectF,startAngle,sweepAngle,false,bgPaint);
        float outCircleRadius=mRectF.width()/2;//带宽度的进度条的中线半径
        
        if(sweepGradient==null) 
            float centerX=(mRectF.left+mRectF.right)/2;
            float centerY=(mRectF.top+mRectF.bottom)/2;
            //
            int rotateDiff=30;//为了解决圆弧开头出的圆角颜色不正常的问题,30度够用了吧
            int rotateDegree=startAngle-rotateDiff;
            float sweepEndPosition=(rotateDiff+sweepAngle*progress/maxProgress*1.0f)/360;
            LogSuperUtil.i("circle_bar","startAngle="+startAngle+",sweepEndPosition="+sweepEndPosition);
            
            float[] positions=0,rotateDiff*1.0f/360,sweepEndPosition,1;
            sweepGradient = new SweepGradient(centerX,centerY,progressColors,positions);
            Matrix rotateMatrix = new Matrix();
            //设置渐变色
            rotateMatrix.setRotate(rotateDegree, centerX, centerY);//180表示从左侧开始往上渐变
            sweepGradient.setLocalMatrix(rotateMatrix);//sweepGradient默认是从0度方向开始渐变的,所以要逆转一下。
            progressPaint.setShader(sweepGradient);
        
        /*
        if(linearGradient==null) 
            linearGradient = new LinearGradient(0, 0, outCircleRadius*2, 0, progressColors,
                    null, LinearGradient.TileMode.CLAMP);
            progressPaint.setShader(linearGradient);
        */
        //进度条
        canvas.drawArc(mRectF,startAngle,progressSweepAngle,false,progressPaint);
        float anchorAngle=progressSweepAngle+(startAngle-180);

        float anchorCoordRedius=outCircleRadius-barWidth/2;
        double cosValue=Math.cos(Math.toRadians(anchorAngle));
        double sinValue=Math.sin(Math.toRadians(anchorAngle));

        float diffByAnchor=anchorBgRadius-barWidth/2;//x和y的偏移正好都是这个
        //float cx=(float)(outCircleRadius-cosValue*anchorCoordRedius+diffByAnchor);
        float cx=(float)(outCircleRadius-cosValue*outCircleRadius+anchorBgRadius);
        //float cy=(float)(outCircleRadius-sinValue*anchorCoordRedius+diffByAnchor);
        float cy=(float)(outCircleRadius-sinValue*outCircleRadius+anchorBgRadius);
        canvas.drawCircle(cx-xDiff,cy,anchorRadius,anchorPaint);//锚点小圆
        canvas.drawCircle(cx-xDiff,cy,anchorBgRadius,anchorBgPaint);//锚点背景大圆
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //int height=measureSize(defaultSize,heightMeasureSpec);
        //int width=measureSize(defaultSize,widthMeasureSpec);
        //startAngle是计算出来的,因为弦的这种,没法通过观察直接得出圆弧的起始角度
        //通过数学计算得知x
        //x是圆心(圆弧所在的圆的圆心)到弦(也就是圆弧的底部)的垂直距离
        float x=(circleWidth*circleWidth-4*circleHeight*circleHeight)/(8*circleHeight);
        //画圆弧用到的圆的半径
        float r=x+circleHeight;
        //int r=(int)(circleWidth/2/Math.cos(Math.toRadians(startAngle-180)));
        //弦长/2/半径=cos(startAngle-180)
        //(startAngle-180)
        double asin=Math.asin(circleWidth/2/r);
        //LogSuperUtil.i("circle_bar","asin="+asin);
        int a=(int)Math.toDegrees(asin);
        //LogSuperUtil.i("circle_bar","a="+a);
        startAngle=180+(90-a);
        sweepAngle=2*a;
        //int min=Math.max(width,height);//获取View最短边的长度
        int width=(int)(Math.sqrt(Math.pow(r+anchorBgRadius,2)-Math.pow(x,2))*2+0.5f+anchorBgRadius);//圆弧的宽度
        width=(int)(2*(circleWidth/2+anchorBgRadius)+0.5f);
        int height=(int)(circleHeight+anchorBgRadius+0.5f+anchorBgRadius);
        //height=width;
        xDiff=r-circleWidth/2;//画布是从最左边开始画圆且显示的,不偏移的话,显示的效果不对。
        LogSuperUtil.i("circle_bar","xDiff="+xDiff);
        setMeasuredDimension(width,height);
        if(Math.min(width,height)>=barWidth*2) //这里简单限制了圆弧的最大宽度
            //1.mRectF决定着圆画在哪个框框里面
            //2.mRectF在当前View中,但不是完全占据当前View
            //3.弧度的粗细画的时候是均分到圆半径线的两侧的
            //4.之所以矩形设置的四个点有偏移,是因为有弧度宽度。
            //因为锚点也有宽度,点再次做调整.
            //mRectF.set(barWidth/2,barWidth/2,min-barWidth/2,min-barWidth/2);
            float diffByAnchor=anchorBgRadius-barWidth/2;//受锚点影响需要修正的偏移
            //是整个圆的矩形,不是弧形区域所在的矩形
            mRectF.set(barWidth/2+diffByAnchor-xDiff,barWidth/2+diffByAnchor,barWidth/2+diffByAnchor+2*r-xDiff,barWidth/2+diffByAnchor+2*r);
        
    
    private int measureSize(int defaultSize,int measureSpec) 
        int result=defaultSize;
        int specMode= MeasureSpec.getMode(measureSpec);
        int specSize= MeasureSpec.getSize(measureSpec);
        if(specMode== MeasureSpec.EXACTLY) 
            LogSuperUtil.i("circle_bar","=EXACTLY");
            result=specSize;
        else if(specMode== MeasureSpec.AT_MOST) 
            LogSuperUtil.i("circle_bar","=AT_MOST");
            result=Math.min(result,specSize);
        else 
            LogSuperUtil.i("circle_bar","=defaultSize");
        
        return result;
    
    private TextView textView;
    private OnAnimationListener onAnimationListener;
    public class CircleBarAnim extends Animation 
        public CircleBarAnim() 

        

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) 
            super.applyTransformation(interpolatedTime, t);
            progressSweepAngle=interpolatedTime*sweepAngle*progress/maxProgress;//这里计算进度条的比例
            postInvalidate();
            if(textView!=null&&onAnimationListener!=null) 
                textView.setText(onAnimationListener.howToChangeText(interpolatedTime,progress,maxProgress));
            
        
    

    /**
     * 设置显示文字的TextView
     * @param textView
     */
    public void setTextView(TextView textView) 
        this.textView=textView;
    
    /*
    * circleBarView.setOnAnimationListener(new CircleBarView.OnAnimationListener() 
	@Override
	public String howToChangeText(float interpolatedTime, float progressNum, float maxNum) 
		DecimalFormat decimalFormat=new DecimalFormat("0.00");
		String s = decimalFormat.format(interpolatedTime * progressNum / maxNum * 100) + "%";
		return s;
	
);


    public interface OnAnimationListener 
        /**
         * 如何处理要显示的文字内容
         * @param interpolatedTime 从0渐变成1,到1时结束动画
         * @param progressNum 进度条数值
         * @param maxNum 进度条最大值
         * @return
         */
        String howToChangeText(float interpolatedTime, float progressNum, float maxNum);
    
    //写个方法给外部调用,用来设置动画时间
    public void setProgress(float progress,int time) 
        anim.setDuration(time);
        this.startAnimation(anim);
        this.progress=progress;
    
    public static int dip2px(Context context,float dpValue) 
        float scale=context.getResources().getDisplayMetrics().density;
        return (int)(dpValue*scale+0.5f);
    
    public static int px2dip(Context context,float pxValue) 
        float scale=context.getResources().getDisplayMetrics().density;
        return (int)(pxValue/scale+0.5f);
    

    /**
     * //extraDistance比较小时,TextView离圆弧很近,是正常,因为TextView是从其自身的左上角开始渲染。
     * @param sweepAnglePercent
     * @param extraDistance
     * @return
     */
    public float getAngleX(float sweepAnglePercent,int extraDistance) 
        float outCircleRadius=mRectF.width()/2+barWidth/2;//带宽度的进度条的外圆半径
        float diffByAnchor=anchorBgRadius-barWidth/2;//x和y的偏移正好都是这个
        float x=(float)(outCircleRadius+diffByAnchor-Math.cos(Math.toRadians(startAngle-180+sweepAnglePercent*sweepAngle))*(outCircleRadius+dip2px(getContext(),extraDistance))-xDiff);
        return x;
    
    private static final String TAG="circle_bar";
    /**
     * 在当前View中的y坐标
     * (注意,TextView渲染的时候,这个坐标是作为TextView控件的左上角进行渲染。
     * 所以,extraDistance小的话,显示的结果TextView可能还在当前View的内部呢,但TextView的左上角是在圆外部的。
     * @param sweepAnglePercent
     * @param extraDistance 从外圆算的往外扩展的距离,不是从锚点背景边缘往外扩展。
     * @return
     */
    public float getAngleY(float sweepAnglePercent,int extraDistance) 
        float outCircleRadius=mRectF.width()/2+barWidth/2;//带宽度的进度条的外圆半径
        float diffByAnchor=anchorBgRadius-barWidth/2;//x和y的偏移正好都是这个
        float coordA=startAngle-180+sweepAnglePercent*sweepAngle;
        LogSuperUtil.i("circle_bar","coordA="+coordA);
        float coordY=(float)Math.sin(Math.toRadians(coordA))*(outCircleRadius+dip2px(getContext(),extraDistance));
        LogSuperUtil.i("circle_bar","coordY="+coordY);
        float tempR=outCircleRadius+diffByAnchor;
        LogSuperUtil.i("circle_bar","tempR="+tempR+",="+circleWidth);//CircleWidth是圆弧宽度
        LogSuperUtil.i("circle_bar","mRectF.width()/2="+mRectF.width()/2);
        float y=(float) (tempR-coordY);
        return y;
    

然后,是那个背景是圆(圆有渐变色和内间距)的文字控件的源码:

/**
 * 表示用户等级的文字,可以设置背景色、圆环色、圆弧与背景的内间距
 * Created by yfx on 2022/10/20 16:36
 */
public class CircleBarTextView extends AppCompatTextView 
    private Paint mPaintBg;
    private Paint mPaintRing;
    private float mRadiusBg;
    private float mRadiusRing;
    private float mRingStrokeWidth;
    private float mPaddingRing2Bg;
    private boolean mIsBgShow;
    private boolean mIsRingShow;
    private int[] ringColors;//进度条圆弧颜色
    private int[] bgColors;//
    private LinearGradient linearGradientRing;
    private LinearGradient linearGradientBg;
    public CircleBarTextView(Context context, @Nullable AttributeSet attrs) 
        super(context, attrs);
        init(context,attrs);
    
    private void init(Context context,AttributeSet attrs) 
        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CircleTextView);
        int ringColor1 = typedArray.getColor(R.styleable.CircleTextView_ringColor1,Color.RED);
        int ringColor2 = typedArray.getColor(R.styleable.CircleTextView_ringColor2,ringColor1);
        //int color3 = typedArray.getColor(R.styleable.CircleTextView_ringColor3,color2);//写法巧妙
        ringColors=new int[]ringColor1,ringColor2;
        int bgColor1 = typedArray.getColor(R.styleable.CircleTextView_bgColor1,Color.RED);
        int bgColor2 = typedArray.getColor(R.styleable.CircleTextView_bgColor2,bgColor1);
        //int color3 = typedArray.getColor(R.styleable.CircleTextView_ringColor3,color2);//写法巧妙
        bgColors=new int[]bgColor1,bgColor2;
        mPaddingRing2Bg = typedArray.getDimension(R.styleable.CircleTextView_paddingRing2Bg,0);//写法巧妙
        mRingStrokeWidth = typedArray.getDimension(R.styleable.CircleTextView_ringStrokeWidth,0);//写法巧妙
        //
        mPaintBg=new Paint();
        mPaintBg.setColor(bgColor1);
        mPaintBg.setStyle(Paint.Style.FILL);
        mPaintBg.setAntiAlias(true);
//
        mPaintRing=new Paint();
        mPaintBg.setColor(ringColor1);
        mPaintRing.setStyle(Paint.Style.STROKE);
        mPaintRing.setStrokeWidth(mRingStrokeWidth);
        mPaintRing.setAntiAlias(true);


    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /*
        int width=mRadiusRing*2;
        int height=mRadiusRing*2;
        setMeasuredDimension(width,height);*/
    

    @Override
    protected void onDraw(Canvas canvas) 
        float cx=getWidth()/2;
        float cy=getWidth()/2;
        mRadiusRing=getWidth()/2-mRingStrokeWidth/2;
        mRadiusBg=mRadiusRing-mPaddingRing2Bg-mRingStrokeWidth/2;
        //渐变色设置
        if(linearGradientRing==null) 
            float r=mRadiusRing+mRingStrokeWidth/2;
            float x0=(float)(r-r/Math.sqrt(2));
            float y0=(float)(r+r/Math.sqrt(2));
            float x1=(float)(r+r/Math.sqrt(2));
            float y1=(float)(r-r/Math.sqrt(2));
            linearGradientRing = new LinearGradient(x0, y0, x1, y1, ringColors,
                    null, LinearGradient.TileMode.CLAMP);
            mPaintRing.setShader(linearGradientRing);
        

        if(linearGradientBg==null) 
            float r=mRadiusRing+mRingStrokeWidth/2;//还是根据最大圆来计算
            float x0=r-mRingStrokeWidth-mPaddingRing2Bg;
            float y0=r;
            float x1=r+mRadiusBg;
            float y1=r;
            //左下到右上的线性渐变
            linearGradientBg = new LinearGradient(x0, y0, x1, y1, bgColors,
                    null, LinearGradient.TileMode.CLAMP);
            mPaintBg.setShader(linearGradientBg);
        
        if(mIsBgShow) 
            canvas.drawCircle(cx,cy,mRadiusBg,mPaintBg);
        

        if(mIsRingShow) 
            canvas.drawCircle(cx,cy,mRadiusRing,mPaintRing);
        
        //canvas.drawtext
        super.onDraw(canvas);
    
    public static int dip2px(Context context,float dpValue) 
        float scale=context.getResources().getDisplayMetrics().density;
        return (int)(dpValue*scale+0.5f);
    
    public void setBgShow(boolean isShow) 
        mIsBgShow=isShow;
        postInvalidate();
    
    public void setRingShow(boolean isShow) 
        mIsRingShow=isShow;
        postInvalidate();
    

自定义属性:

<declare-styleable name="CircleBarView">
    <attr name="progress_color1" format="reference|color"></attr>
    <attr name="progress_color2" format="reference|color"></attr>
    <attr name="progress_color3" format="reference|color"></attr>
    <attr name="bg_color" format="color"></attr>
    <attr name="bar_width" format="dimension"></attr>
    <attr name="circle_width" format="dimension"></attr><!--背景圆弧宽度 -->
    <attr name="circle_height" format="dimension"></attr><!--背景圆弧高度 -->
    <attr name="anchor_radius" format="dimension"></attr>
    <attr name="anchor_bg_radius" format="dimension"></attr>
    <attr name="anchor_color" format="reference|color"></attr>
    <attr name="anchor_bg_color" format="reference|color"></attr>
    <attr name="progress_max" format="integer"></attr>
</declare-styleable>
<declare-styleable name="CircleTextView">
    <attr name="paddingRing2Bg" format="dimension"></attr>
    <attr name="ringStrokeWidth" format="dimension"></attr>
    <attr name="ringColor1" format="reference|color"></attr>
    <attr name="ringColor2" format="reference|color"></attr>
    <attr name="bgColor1" format="reference|color"></attr>
    <attr name="bgColor2" format="reference|color"></attr>
</declare-styleable>

文字的位置需要处理,使用时有几个细节需要注意,我们下篇再具体介绍。

紧急联系请家伟信ye10612424091

Android 自定义漂亮的圆形进度条

这几天对Android中实现画圆弧及圆弧效果中所实现的效果进行了修改,改为进度圆心进度条,效果如图所示




技术图片 




TasksCompletedView.java 代码如下

 

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Paint.FontMetrics;
import android.util.AttributeSet;
import android.view.View;

import com.snailws.taskscompleted.R;

/**
* @author naiyu(http://snailws.com)
* @version 1.0
*/
public class TasksCompletedView extends View {

        // 画实心圆的画笔
        private Paint mCirclePaint;
        // 画圆环的画笔
        private Paint mRingPaint;
        // 画字体的画笔
        private Paint mTextPaint;
        // 圆形颜色
        private int mCircleColor;
        // 圆环颜色
        private int mRingColor;
        // 半径
        private float mRadius;
        // 圆环半径
        private float mRingRadius;
        // 圆环宽度
        private float mStrokeWidth;
        // 圆心x坐标
        private int mXCenter;
        // 圆心y坐标
        private int mYCenter;
        // 字的长度
        private float mTxtWidth;
        // 字的高度
        private float mTxtHeight;
        // 总进度
        private int mTotalProgress = 100;
        // 当前进度
        private int mProgress;

        public TasksCompletedView(Context context, AttributeSet attrs) {
                super(context, attrs);
                // 获取自定义的属性
                initAttrs(context, attrs);
                initVariable();
        }

        private void initAttrs(Context context, AttributeSet attrs) {
                TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs,
                                R.styleable.TasksCompletedView, 0, 0);
                mRadius = typeArray.getDimension(R.styleable.TasksCompletedView_radius, 80);
                mStrokeWidth = typeArray.getDimension(R.styleable.TasksCompletedView_strokeWidth, 10);
                mCircleColor = typeArray.getColor(R.styleable.TasksCompletedView_circleColor, 0xFFFFFFFF);
                mRingColor = typeArray.getColor(R.styleable.TasksCompletedView_ringColor, 0xFFFFFFFF);
                
                mRingRadius = mRadius + mStrokeWidth / 2;
        }

        private void initVariable() {
                mCirclePaint = new Paint();
                mCirclePaint.setAntiAlias(true);
                mCirclePaint.setColor(mCircleColor);
                mCirclePaint.setStyle(Paint.Style.FILL);
                
                mRingPaint = new Paint();
                mRingPaint.setAntiAlias(true);
                mRingPaint.setColor(mRingColor);
                mRingPaint.setStyle(Paint.Style.STROKE);
                mRingPaint.setStrokeWidth(mStrokeWidth);
                
                mTextPaint = new Paint();
                mTextPaint.setAntiAlias(true);
                mTextPaint.setStyle(Paint.Style.FILL);
                mTextPaint.setARGB(255, 255, 255, 255);
                mTextPaint.setTextSize(mRadius / 2);
                
                FontMetrics fm = mTextPaint.getFontMetrics();
                mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent);
                
        }

        @Override
        protected void onDraw(Canvas canvas) {

                mXCenter = getWidth() / 2;
                mYCenter = getHeight() / 2;
                
                canvas.drawCircle(mXCenter, mYCenter, mRadius, mCirclePaint);
                
                if (mProgress > 0 ) {
                        RectF oval = new RectF();
                        oval.left = (mXCenter - mRingRadius);
                        oval.top = (mYCenter - mRingRadius);
                        oval.right = mRingRadius * 2 + (mXCenter - mRingRadius);
                        oval.bottom = mRingRadius * 2 + (mYCenter - mRingRadius);
                        canvas.drawArc(oval, -90, ((float)mProgress / mTotalProgress) * 360, false, mRingPaint); //
//                        canvas.drawCircle(mXCenter, mYCenter, mRadius + mStrokeWidth / 2, mRingPaint);
                        String txt = mProgress + "%";
                        mTxtWidth = mTextPaint.measureText(txt, 0, txt.length());
                        canvas.drawText(txt, mXCenter - mTxtWidth / 2, mYCenter + mTxtHeight / 4, mTextPaint);
                }
        }
        
        public void setProgress(int progress) {
                mProgress = progress;
//                invalidate();
                postInvalidate();
        }

}

attrs.xml

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    
    <declare-styleable name="TasksCompletedView">
        <attr name="radius" format="dimension"/>
        <attr name="strokeWidth" format="dimension"/>
        <attr name="circleColor" format="color"/>
        <attr name="ringColor" format="color"/>
    </declare-styleable>
    
</resources>

源码下载:http://download.csdn.net/detail/nainai007/6554501

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow















以上是关于Android自定义圆弧进度条(半圆进度条) 圆弧渐变色进度条带指示 圆弧宽高可自由修改的主要内容,如果未能解决你的问题,请参考以下文章

Android自定义圆弧进度条

Android 自定义漂亮的圆形进度条

Android 自定义View——动态进度条

首页2--动态自定义圆形进度条

Android自定义控件系列案例

求教 android半圆弧形的进度条问题