Android 自定義控制元件圓形進度條末端帶原點

2020-09-29 14:00:48

先上效果圖
在這裡插入圖片描述

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