Android弧形ProgressBar、SeekBar

germo發表於2021-09-09

網上有很多弧形或者圓形的ProgressBar和SeekBar。前幾天無意中發現一個弧形的ProgressBar覺得挺不錯的,就下載來看看原始碼。

執行他的Demo的時候發現幾個問題,並且有些問題在issue裡面也有人提出了,但是作者一直沒有回覆,我把問題修復之後加上了Seek的功能,讓它能當做SeekBar用。

原作者的Demo效果圖

圖片描述


存在的問題:

  1. 不能透過XML配置控制元件的大小,原始碼裡面寫死了,寫成佔螢幕的百分比。

  2. 有幾個屬性的顏色值設定無效。比如預設的弧形背景色

  3. 放大縮小控制元件之後對應的字型沒有相應的調整大小

需要考慮的問題點:

我們從最下面帶刻度帶提示的效果圖入手

####我們呢先分析原作者的程式碼:

package com.shinelw.colorarcprogressbar;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PaintFlagsDrawFilter;import android.graphics.RectF;import android.graphics.SweepGradient;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.View;import android.view.WindowManager;/**
 * colorful arc progress bar
 * Created by shinelw on 12/4/15.
 */public class ColorArcProgressBar extends View{

    private int mWidth;    private int mHeight;    //直徑
    private int diameter = 500;    private RectF bgRect;    //圓心
    private float centerX;    private float centerY;    private Paint allArcPaint;    private Paint progressPaint;    private Paint vTextPaint;    private Paint hintPaint;    private Paint degreePaint;    private Paint curSpeedPaint;    private float startAngle = 135;    private float sweepAngle = 270;    private float currentAngle = 0;    private float lastAngle;    private int[] colors = {Color.GREEN, Color.YELLOW, Color.RED, Color.RED};    private ValueAnimator progressAnimator;    private float maxValues = 60;    private float curValues = 0;    private int bgArcWidth = dipToPx(2);    private int progressWidth = dipToPx(10);    private int textSize = dipToPx(80);    private int hintSize = dipToPx(22);    private int curSpeedSize = dipToPx(13);    private int aniSpeed = 1000;    private int longdegree = dipToPx(13);    private int shortdegree = dipToPx(5);    private final int DEGREE_PROGRESS_DISTANCE = dipToPx(8);    private String hintColor = "#676767";    private String longDegreeColor = "#d2d2d2";    private String shortDegreeColor = "#adadad";    private String bgArcColor = "#111111";    private boolean isShowCurrentSpeed = true;    private String hintString = "Km/h";    // sweepAngle / maxValues 的值
    private float k;    public ColorArcProgressBar(Context context) {        super(context);
        initView();
    }    public ColorArcProgressBar(Context context, AttributeSet attrs) {        super(context, attrs);
        initView();
    }    public ColorArcProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);
        initView();
    }    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int width = 2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE;        int height= 2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE;
        setMeasuredDimension(width, height);
    }    private void initView() {

        diameter = 3 * getScreenWidth() / 5;        //弧形的矩陣區域
        bgRect = new RectF();
        bgRect.top = longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE;
        bgRect.left = longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE;
        bgRect.right = diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE);
        bgRect.bottom = diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE);        //圓心
        centerX = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE)/2;
        centerY = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE)/2;        //外部刻度線
        degreePaint = new Paint();
        degreePaint.setColor(Color.parseColor(longDegreeColor));        //整個弧形
        allArcPaint = new Paint();
        allArcPaint.setAntiAlias(true);
        allArcPaint.setStyle(Paint.Style.STROKE);
        allArcPaint.setStrokeWidth(bgArcWidth);
        allArcPaint.setColor(Color.parseColor(bgArcColor));
        allArcPaint.setStrokeCap(Paint.Cap.ROUND);        //當前進度的弧形
        progressPaint = new Paint();
        progressPaint.setAntiAlias(true);
        progressPaint.setStyle(Paint.Style.STROKE);
        progressPaint.setStrokeCap(Paint.Cap.ROUND);
        progressPaint.setStrokeWidth(progressWidth);
        progressPaint.setColor(Color.GREEN);        //當前速度顯示文字
        vTextPaint = new Paint();
        vTextPaint.setTextSize(textSize);
        vTextPaint.setColor(Color.WHITE);
        vTextPaint.setTextAlign(Paint.Align.CENTER);        //顯示“km/h”文字
        hintPaint = new Paint();
        hintPaint.setTextSize(hintSize);
        hintPaint.setColor(Color.parseColor(hintColor));
        hintPaint.setTextAlign(Paint.Align.CENTER);        //顯示“km/h”文字
        curSpeedPaint = new Paint();
        curSpeedPaint.setTextSize(curSpeedSize);
        curSpeedPaint.setColor(Color.parseColor(hintColor));
        curSpeedPaint.setTextAlign(Paint.Align.CENTER);



    }    @Override
    protected void onDraw(Canvas canvas) {        //抗鋸齒
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));        //畫刻度線
        for (int i = 0; i  15 && i  maxValues) {
            currentValues = maxValues;
        }        if (currentValues = 0 ? 1 : -1));
    }    /**
     * 得到螢幕寬度
     * @return
     */
    private int getScreenWidth() {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);        return displayMetrics.widthPixels;
    }    public void setIsShowCurrentSpeed(boolean isShowCurrentSpeed) {        this.isShowCurrentSpeed = isShowCurrentSpeed;
    }    /**
     * 初始載入頁面時設定載入動畫
     */
    public void setDefaultWithAnimator() {
        setAnimation(sweepAngle, currentAngle, 2000);
    }



}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321

從以上程式碼可以看出:

  • 在initView 的時候設定了弧形的直徑diameter = 3 * getScreenWidth() / 5;也就是弧形的直徑是根據螢幕的大小定的。 
    我們再看OnMeasure方法

     @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int width = 2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE;        int height= 2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE;
            setMeasuredDimension(width, height);
        }

所以我們知道:不管你怎麼設定控制元件的寬高,都沒有效果。這是第一個問題

  • 設定某些顏色值無效的問題: 
    顏色值的設定是通常作用於畫筆上,我們先看看幾個畫筆:

        private Paint allArcPaint;//背景弧形的畫筆(圓弧)
        private Paint progressPaint;//進度畫筆(當前速度)
        private Paint vTextPaint;//內容文字畫筆(80)
        private Paint hintPaint;//單位文字畫筆(km/h)
        private Paint degreePaint;//刻度畫筆(刻度條)
        private Paint curSpeedPaint;//標題文字畫筆(當前速度)

這些畫筆的顏色值在initView的時候初始化,但是顏色值並沒有在initConfig的時候取出屬性值並且配置,所以這是導致設定顏色無效的原因

注意:給畫筆設定的顏色值必須帶有透明度,不然會自動帶上全透明效果。看不到任何資訊

  • 調整控制元件大小的時候圓弧內的文字沒有做出大小和位置的調整 
    在原始碼中,initView的時候就已經設定TextSize了,而initView是在例項化的時候呼叫的,這時候控制元件的大小都還沒有確定,所以需要把和大小相關的值都放到OnSizeChange中,或者在OnMeasure中獲取控制元件的實際大小之後再初始化這些值

    @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh)
        {            super.onSizeChanged(w, h, oldw, oldh);
            mWidth = w;
            mHeight = h;
            Log.v("ColorArcProgressBar", "onSizeChanged: mWidth:" + mWidth + " mHeight:" + mHeight);

            diameter = (int) (Math.min(mWidth, mHeight) - 2 * (longDegree + DEGREE_PROGRESS_DISTANCE + progressWidth / 2));

            Log.v("ColorArcProgressBar", "onSizeChanged: diameter:" + diameter);            //弧形的矩陣區域
            bgRect = new RectF();
            bgRect.top = longDegree + DEGREE_PROGRESS_DISTANCE + progressWidth / 2;
            bgRect.left = longDegree + DEGREE_PROGRESS_DISTANCE + progressWidth / 2;
            bgRect.right = diameter + (longDegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE);
            bgRect.bottom = diameter + (longDegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE);

            Log.v("ColorArcProgressBar", "initView: " + diameter);            //圓心
            centerX = (2 * (longDegree + DEGREE_PROGRESS_DISTANCE + progressWidth / 2) + diameter) / 2;
            centerY = (2 * (longDegree + DEGREE_PROGRESS_DISTANCE + progressWidth / 2) + diameter) / 2;

            sweepGradient = new SweepGradient(centerX, centerY, colors, null);

            mTouchInvalidateRadius = Math.max(mWidth, mHeight) / 2 - longDegree - DEGREE_PROGRESS_DISTANCE - progressWidth * 2;            if(isAutoTextSize)
            {
                textSize = (float) (diameter * 0.3);
                hintSize = (float) (diameter * 0.1);
                curSpeedSize = (float) (diameter * 0.1);

                vTextPaint.setTextSize(textSize);
                hintPaint.setTextSize(hintSize);
                curSpeedPaint.setTextSize(curSpeedSize);
            }

        }

透過在OnSizeChange中初始化這些動態的尺寸,就解決了文字縮放的問題。


原文連結:http://www.apkbus.com/blog-865069-78319.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1868/viewspace-2806089/,如需轉載,請註明出處,否則將追究法律責任。

相關文章