Android 自定义控件圆形进度条末端带原点

先上效果图
在这里插入图片描述

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * 自定义带圆点的进度条
 */
public class HalfProgressBar extends View {

    /**
     * 当前进度
     */
    private int progress = 150;
    /**
     * 最大进度
     */
    private int maxProgress = 360;
    //设置进度条背景宽度
    private float progressStrokeWidth = 15;
    //设置进度条进度宽度
//    private float marxArcStorkeWidth = 6;
    //设置进度条圆点的宽度
    private float circularDotWidth = 30;


    /**
     * 画笔对象的引用
     */
    private Paint paintBackGround;
    private Paint paintProgress;
    private Paint paintDot;
    private float progressTextSize;

    public synchronized int getProgress() {
        return progress;
    }

    /**
     * Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。
     * 而postInvalidate()在工作者线程中被调用 使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。
     *
     * @param progress 传过来的进度
     */
    public void setProgress(int progress) {
        if (progress < 0) {
            progress = 0;
        }
        if (progress > maxProgress) {
            progress = maxProgress;
        }
        if (progress <= maxProgress) {
            this.progress = progress;
            postInvalidate();
        }
    }



    private RectF oval;
    private int roundProgressColor;
    private int roundColor;
    private int circularDotColor;
    private int progressTextColor;

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

    public HalfProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

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

    private void init(Context context, AttributeSet attrs) {
        paintBackGround = new Paint();
        paintProgress = new Paint();
        paintDot = new Paint();
        oval = new RectF();
        //这是自定义view 必须要写的
        TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.MyHalfProgressBar);
        roundProgressColor = mTypedArray.getColor(R.styleable.MyHalfProgressBar_roundProgressColor1, Color.YELLOW);
        roundColor = mTypedArray.getColor(R.styleable.MyHalfProgressBar_roundColor1, Color.YELLOW);
        circularDotColor = mTypedArray.getColor(R.styleable.MyHalfProgressBar_circularDotColor1, Color.YELLOW);
        progressTextSize = mTypedArray.getDimension(R.styleable.MyHalfProgressBar_progressTextSize, 15);
        progressTextColor = mTypedArray.getInteger(R.styleable.MyHalfProgressBar_progressTextColor, Color.YELLOW);
    }

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float width = getWidth();
    float height = getWidth();
    paintBackGround.setAntiAlias(false); // 设置画笔为抗锯齿
    paintBackGround.setColor(roundColor); // 设置画笔颜色
    paintBackGround.setStrokeWidth(progressStrokeWidth); // 线宽
    paintBackGround.setStyle(Paint.Style.STROKE);

    //进度条颜色
    paintProgress.setColor(roundProgressColor);
    paintProgress.setStrokeWidth(progressStrokeWidth);
    paintProgress.setAntiAlias(false); // 设置画笔为抗锯齿
    paintProgress.setStyle(Paint.Style.STROKE);

    oval.left = circularDotWidth / 2; //
    oval.top = circularDotWidth/2; //
    oval.right = width - circularDotWidth / 2; //
    oval.bottom = width - circularDotWidth / 2; //
    float banjing = (width/2 - progressStrokeWidth / 2);//半径
    //调整圆背景的大小
    canvas.drawArc(oval, 360, 360, false, paintBackGround); // 绘制红丝圆圈,即进度条背景
    Log.i("banjing",":"+banjing);
    Log.i("banjing","width:"+width);

    canvas.drawArc(oval, 180, progress, false, paintProgress); // 绘制进度圆弧,这里是蓝色


    //画圆点
    paintDot.setColor(circularDotColor);
    paintDot.setAntiAlias(true); // 设置画笔为抗锯齿
    paintDot.setStyle(Paint.Style.FILL);
    paintDot.setStrokeWidth(circularDotWidth);
    //当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式Cap.ROUND,或方形样式Cap.SQUARE
    paintDot.setStrokeCap(Paint.Cap.ROUND);
    float jindu = ((float) progress * 1.7f);
    double a=0;
    float  x=0;
    float  y=0;
    float  v=0;
    float  v1=0;

    if (progress<90){
        a = (Math.PI / (double) 180) * (90-progress);
        v = (float) (Math.sin(a)) * banjing;
        v1 = (float) (Math.cos(a)) * banjing;
        x = width/2 + progressStrokeWidth / 2 - v;
        y = width/2 + progressStrokeWidth / 2 - v1;
    }
    if (progress==90){
        x = width/2 ;
        y = circularDotWidth/2;
    }
    if (progress>90&&progress<180){
        a = (Math.PI / (double) 180) * (180-progress);
        v = (float) (Math.sin(a)) * banjing;
        v1 = (float) (Math.cos(a)) * banjing;
        if (progress>=150){
            x = width/2 - progressStrokeWidth / 2 + v1;
            y = width/2 - v;
        }else {
            x = width/2 + v1;
            y = width/2 + progressStrokeWidth/2 - v;
        }

    }
    if (progress==180){
        x = width -progressStrokeWidth;
        y = width/2;
    }
    if (progress>180&&progress<270){
        a = (Math.PI / (double) 180) * (270-progress);
        v = (float) (Math.sin(a)) * banjing;
        v1 = (float) (Math.cos(a)) * banjing;
        if (progress>=240){
            x = width/2 - progressStrokeWidth / 2 + v;
            y = width/2 - progressStrokeWidth / 2 + v1;
        }else {
            x = width/2 - progressStrokeWidth / 2 + v;
            y = width/2 + v1;
        }

    }
    	if (progress==270){
	//            a = (Math.PI / (double) 180) * (270-progress);
	//            v = (float) (Math.sin(a)) * banjing;
	//            v1 = (float) (Math.cos(a)) * banjing;
        x = width/2;
        y = width - progressStrokeWidth ;
    }
    if (progress>270){
        a = (Math.PI / (double) 180) * (360-progress);
        v = (float) (Math.sin(a)) * banjing;
        v1 = (float) (Math.cos(a)) * banjing;
        x = width/2 + progressStrokeWidth / 2 - v1;
        y = width/2 - progressStrokeWidth / 2 + v;
    }
    canvas.drawPoint(x, y, paintDot);

    Log.i("banjing",",a:"+a);
    Log.i("banjing",",x:"+x);
    Log.i("banjing",",y:"+y);
    Log.i("banjing",",v:"+v);
    Log.i("banjing",",v1:"+v1);

    //绘制中间文本
    String testProgress =( (int)progress*100/360)+"%";
    TextPaint mPaint = new TextPaint();
    mPaint.setStrokeWidth(7);
    mPaint.setTextSize(progressTextSize);
    mPaint.setTypeface(Typeface.DEFAULT_BOLD);
    mPaint.setColor(progressTextColor);
    mPaint.setTextAlign(Paint.Align.LEFT);
    Rect bounds = new Rect();
    mPaint.getTextBounds(testProgress, 0, testProgress.length(), bounds);
    Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
    int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
    canvas.drawText(testProgress,getMeasuredWidth() / 2 - bounds.width() / 2, baseline, mPaint);



}

}

<declare-styleable name="MyHalfProgressBar">
    <attr name="roundColor1" format="color"/>
    <attr name="roundProgressColor1" format="color"/>
    <attr name="circularDotColor1" format="color"/>
    <attr name="progressTextColor" format="color"/>
    <attr name="progressTextSize" format="dimension"/>
</declare-styleable>

#44c8da
#4444c8da

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
总共分为三层:一层为圆形边线,一层为进度边线,一层用来显示标识进度节点。 public class CircleProgressBar extends View { private int maxProgress = 100; private int progress = 15; private int progressStrokeWidth = 2; private int marxArcStorkeWidth = 16; // 圆所在的距形区域 RectF oval; Paint paint; public CircleProgressBar(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub oval = new RectF(); paint = new Paint(); } @Override protected void onDraw(Canvas canvas) { // TODO 自动生成的方法存根 super.onDraw(canvas); int width = this.getWidth(); int height = this.getHeight(); width = (width > height) ? height : width; height = (width > height) ? height : width; paint.setAntiAlias(true); // 设置笔为抗锯齿 paint.setColor(Color.WHITE); // 设置笔颜色 canvas.drawColor(Color.TRANSPARENT); // 白色背景 paint.setStrokeWidth(progressStrokeWidth); // 线宽 paint.setStyle(Style.STROKE); oval.left = marxArcStorkeWidth / 2; // 左上角x oval.top = marxArcStorkeWidth / 2; // 左上角y oval.right = width - marxArcStorkeWidth / 2; // 左下角x oval.bottom = height - marxArcStorkeWidth / 2; // 右下角y canvas.drawArc(oval, -90, 360, false, paint); // 绘制白色圆圈,即进度条背景 paint.setColor(Color.rgb(0x57, 0x87, 0xb6)); paint.setStrokeWidth(marxArcStorkeWidth); canvas.drawArc(oval, -90, ((float) progress / maxProgress) * 360, false, paint); // 绘制进度圆弧,这里是蓝色 paint.setStrokeWidth(1); String text = progress + "%"; int textHeight = height / 4; paint.setTextSize(textHeight); int textWidth = (int) paint.measureText(text, 0, text.length()); paint.setStyle(Style.FILL); canvas.drawText(text, width / 2 - textWidth / 2, height / 2 + textHeight / 2, paint); } public int getMaxProgress() { return maxProgress; } public void setMaxProgress(int maxProgress) { this.maxProgress = maxProgress; } /** * 设置进度 * * @param progress * 进度百分比 * @param view * 标识进度的节点视图 */ public void setProgress(int progress, View view) { this.progress = progress; view.setAnimation(pointRotationAnima(0, (int) (((float) 360 / maxProgress) * progress))); this.invalidate(); } /** * 非UI线程调用 */ public void setProgressNotInUiThread(int progress, View view) { this.progress = progress; view.setAnimation(pointRotationAnima(0, (int) (((float) 360 / maxProgress) * progress))); this.postInvalidate(); } /** * 进度标注点的动 * * @param fromDegrees * @param toDegrees * @return */ private Animation pointRotationAnima(float fromDegrees, float toDegrees) { int initDegress = 306;// 进度点起始位置(图片偏移约54度) RotateAnimation animation = new RotateAnimation(fromDegrees, initDegress + toDegrees, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); animation.setDuration(1);// 设置动执行时间 animation.setRepeatCount(1);// 设置重复执行次数 animation.setFillAfter(true);// 设置动结束后是否停留在结束位置 return animation; } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值