效果圖:
或
方法講解:
(1)invalidate()方法
invalidate()是用來刷新View的,必須是在UI線程中進行工作。比如在修改某個view的顯示時, 調用invalidate()才能看到重新繪制的界面。invalidate()的調用是把之前的舊的view從主UI線程隊列中pop掉。一般在自定義控件中會用到這個方法。
(2)RectF方法的應用
RectF是用來繪畫矩形的方法。
RectF(left,top,right,bottom),四個參數的含義分別是父控件距離矩形左上右下邊距的距離,以下用圖來說明:
drawRoundRect方法是用來繪制圓角矩形的,它的參數如下:
參數說明
rect:RectF對象。
rx:x方向上的圓角半徑。
ry:y方向上的圓角半徑。
paint:繪制時所使用的畫筆。
(3)onMeasure方法
指定自定義控件在屏幕上的大小,onMeasure方法的兩個參數是由上一層控件 傳入的大小,而且是模式和尺寸混合在一起的數值,需要MeasureSpec.getMode(widthMeasureSpec) 得到模式,MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
onMeasure的幾種模式分別為EXACTLY,AT_MOST,UNSPECIFIED。
[1]MeasureSpec.EXACTLY
MeasureSpec.EXACTLY是精確尺寸,當我們將控件的layout_width或layout_height指定為具體數值時如andorid:layout_width=”50dip”,或者為FILL_PARENT是,都是控件大小已經確定的情況,都是精確尺寸。
[2]MeasureSpec.AT_MOST
MeasureSpec.AT_MOST是最大尺寸,當控件的layout_width或layout_height指定為WRAP_CONTENT時,控件大小一般隨着控件的子空間或內容進行變化,此時控件尺寸只要不超過父控件允許的最大尺寸即可。因此,此時的mode是AT_MOST,size給出了父控件允許的最大尺寸。
[3]MeasureSpec.UNSPECIFIED
MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多,一般都是父控件是AdapterView,通過measure方法傳入的模式。
實現步驟:
a、在values文件夾下新建attrs.xml,內容如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircleProgressBar"> <attr name="croundColor" format="color"/> <attr name="croundProgressColor" format="color"/> <attr name="cfillColor" format="color"/> <attr name="croundWidth" format="dimension"></attr> <attr name="croundProgressWidth" format="dimension"></attr> <attr name="ctextColor" format="color" /> <attr name="ctextSize" format="dimension" /> <attr name="cnumberSize" format="dimension" /> <attr name="cparaLable" format="string" /> <attr name="cunitLable" format="string" /> </declare-styleable> <declare-styleable name="RoundRectProgressBar"> <attr name="cbarRoundColor" format="color"/> <attr name="cbarProgressColor" format="color"/> <attr name="cbarFillColor" format="color"/> <attr name="cbarOrientation"> <enum name="HORIZONTAL" value="0"></enum> <enum name="VERTICAL" value="1"></enum> </attr> </declare-styleable> </resources>
b、新建RoundRectProgressBar類繼承View
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; /** * 自定義圓角矩形進度條view * * @author xl */ public class RoundRectProgressBar extends View { private final static String TAG = RoundRectProgressBar.class.getSimpleName(); /** * 畫筆對象的引用 */ private Paint paint; /** * 圓角環的顏色 */ private int roundColor; /** * 進度的顏色 */ private int fillProgressColor; /** * 填充的顏色 */ private int fillColor; /** * 圓角矩形寬度 */ private int roundWidth; /** * 圓角矩形高度 */ private int roundHeight; /** * 進度條方向,0水平,1垂直 */ private int barOrientation; /** * 進度條最大值 */ private float max = 100; /** * 進度條當前值 */ private float progress = 30; public RoundRectProgressBar(Context context) { this(context, null); } public RoundRectProgressBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RoundRectProgressBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //獲取畫筆 paint = new Paint(); TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundRectProgressBar); //獲取自定義屬性和默認值 roundColor = mTypedArray.getColor(R.styleable.RoundRectProgressBar_cbarRoundColor, Color.RED); fillProgressColor = mTypedArray.getColor(R.styleable.RoundRectProgressBar_cbarProgressColor, Color.GREEN); fillColor = mTypedArray.getColor(R.styleable.RoundRectProgressBar_cbarFillColor, Color.BLUE); barOrientation = mTypedArray.getInt(R.styleable.RoundRectProgressBar_cbarOrientation, 0); //回收TypedArray資源 mTypedArray.recycle(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //設置抗鋸齒效果 paint.setAntiAlias(true); //設置畫筆顏色 paint.setColor(roundColor); //進度方向 if (barOrientation == 0) { //水平,向右 try { int round = roundHeight / 2; //RectF:繪制矩形,四個參數分別是left,top,right,bottom,類型是單精度浮點數 RectF rf = new RectF(0, 0, roundWidth, roundHeight); //繪制圓角矩形,背景色為畫筆顏色 canvas.drawRoundRect(rf, round, round, paint); //設置progress內部是灰色 paint.setColor(fillColor); RectF rectBlackBg = new RectF(2, 2, roundWidth - 2, roundHeight - 2); canvas.drawRoundRect(rectBlackBg, round, round, paint); //設置進度條進度及顏色 float section = progress / max; RectF rectProgressBg = new RectF(2, 2, (roundWidth - 2) * section, roundHeight - 2); if (section != 0.0f) { paint.setColor(fillProgressColor); } else { paint.setColor(Color.TRANSPARENT); } canvas.drawRoundRect(rectProgressBg, round, round, paint); } catch (Exception e) { e.printStackTrace(); } } else { //垂直,向上 try { int round = roundWidth / 2; //RectF:繪制矩形,四個參數分別是left,top,right,bottom,類型是單精度浮點數 RectF rf = new RectF(0, 0, roundWidth, roundHeight); //繪制圓角矩形,背景色為畫筆顏色 canvas.drawRoundRect(rf, round, round, paint); //設置progress內部是灰色 paint.setColor(fillColor); RectF rectBlackBg = new RectF(2, 2, roundWidth - 2, roundHeight - 2); canvas.drawRoundRect(rectBlackBg, round, round, paint); //設置進度條進度及顏色 float section = progress / max; RectF rectProgressBg = new RectF(2, roundHeight - 2 - (roundHeight - 4) * section, roundWidth - 2, roundHeight - 2); if (section != 0.0f) { paint.setColor(fillProgressColor); } else { paint.setColor(Color.TRANSPARENT); } canvas.drawRoundRect(rectProgressBg, round, round, paint); } catch (Exception e) { e.printStackTrace(); } } } /** * dip轉px * * @param dip * @return */ private int dipToPx(int dip) { float scale = getContext().getResources().getDisplayMetrics().density; //加0.5是為了四舍五入 return (int) (dip * scale + 0.5f * (dip >= 0 ? 1 : -1)); } /** * 指定自定義控件在屏幕上的大小,onMeasure方法的兩個參數是由上一層控件 * 傳入的大小,而且是模式和尺寸混合在一起的數值,需要MeasureSpec.getMode(widthMeasureSpec) * 得到模式,MeasureSpec.getSize(widthMeasureSpec)得到尺寸 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); //MeasureSpec.EXACTLY,精確尺寸 if (widthSpecMode == MeasureSpec.EXACTLY || widthSpecMode == MeasureSpec.AT_MOST) { roundWidth = widthSpecSize; } else { roundWidth = 0; } if (heightSpecMode == MeasureSpec.EXACTLY || heightSpecMode == MeasureSpec.AT_MOST) { roundHeight = heightSpecSize; } else { roundHeight = 0; } //MeasureSpec.AT_MOST,最大尺寸,只要不超過父控件允許的最大尺寸即可,MeasureSpec.UNSPECIFIED未指定尺寸 //if (heightSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.UNSPECIFIED) { // roundHeight = dipToPx(20); //} else { // roundHeight = heightSpecSize; //} //設置控件實際大小 setMeasuredDimension(roundWidth, roundHeight); } /** * 設置進度 * * @param progress */ public synchronized void setProgress(float progress) { if (progress < 0) { throw new IllegalArgumentException("value can not be negative"); } if (progress > max) { this.progress = max; } else { this.progress = progress; } postInvalidate(); } /** * 設置最大值 * * @param max */ public synchronized void setMax(float max) { if (max < 0) { throw new IllegalArgumentException("value can not be negative"); } this.max = max; } }
c、布局文件中引用activity_main.xml
<ups.invt.com.view.RoundRectProgressBar android:id="@+id/bar" android:layout_width="20dp" android:layout_height="100dp" android_custom:cbarRoundColor="@color/transparent" android_custom:cbarFillColor="@color/white" android_custom:cbarProgressColor="@color/bar_fill_color" android_custom:cbarOrientation="VERTICAL" android:layout_centerInParent="true"/>
d、MainActivity.java中設置進度
progress = (RoundRectProgressBar) findViewById(R.id.bar); progress.setMax(100); progress.setProgress(80);
完!!!
————————————————
參考於:https://blog.csdn.net/xialong_927/article/details/86596932