自定義一個帶進度值的圓形進度條
阿新 • • 發佈:2019-01-01
專案中有時候我們為了博得使用者的眼球,需要自定義一些好看的控制元件,下面記錄一個自定義帶進度值的圓形進度條
先上效果
下面記錄具體的實現過程
在Android studio下新建一個project,然後新建一個CircleProgressView,繼承系統的view,然後重寫它的三個構造方法,如下:
然後在定義圓形角度條需要的一些引數:public CircleProgressView(Context context) { this(context,null); } public CircleProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; }
我們先不自定義屬性,先在程式碼中使用預設的值。寫一個方法,得到手機的中心點,我們要以這個中心點繪製圓private Context mContext; private Paint mBackgroudPaint;//圓的畫筆 private Paint mFrontPaint;//進度條的畫筆 private Paint mTextPaint;//數字的畫筆 private int mWidth;//控制元件的寬度 private int mHeight;//控制元件的高度 private float redis = 200;//預設圓的半徑 private float roundWidth = 50;//預設圓形進度的寬度 private float textSize = 50;//預設字型的大小 private int progress = 0;//記錄進度值 private int maxProgress = 100;//最大進度值 private int backProgressColor = 0xff778899;//預設背景的顏色 private int roundProgressColor = 0xff00BFFF;//預設圓形進度條的顏色 private int textColor = 0xff008080;//預設字型的顏色 private int mXCenter;//圓心的x座標 private int mYCenter;//圓心的Y座標
然後在構造方法中呼叫getPhoneCenter()方法,獲取到中心點的座標。/** * 得到螢幕的中心點 */ private void getPhoneCenter(){ WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); mXCenter = wm.getDefaultDisplay().getWidth()/2; mYCenter = wm.getDefaultDisplay().getHeight()/2; }
得到中心點的座標後,就可以開始繪製了,重寫onDraw()方法,在onDraw()方法中,我們分別繪製背景圓,進度條的扇形,和進度值的數字
先繪製背景圓:
mBackgroudPaint = new Paint();//初始化背景畫筆
mBackgroudPaint.setColor(backProgressColor);
mBackgroudPaint.setAlpha(100);//透明度 0~255 從完全透明到不透明
mBackgroudPaint.setAntiAlias(true);//消除鋸齒
mBackgroudPaint.setStyle(Paint.Style.FILL);//實心圓
canvas.drawCircle(mXCenter,mYCenter,redis,mBackgroudPaint);//制定中心點的座標,半徑
然後在繪製進度值的數字
mTextPaint = new Paint();//初始化數字的畫筆
mTextPaint.setColor(textColor);//
mTextPaint.setAntiAlias(true);//消除鋸齒
mTextPaint.setTextSize(textSize);//
mTextPaint.setTextAlign(Paint.Align.CENTER);//設定文字的對齊方式
canvas.drawText(progress+"%",mXCenter,mYCenter, mTextPaint);//progress是載入的進度值
最後就是繪製進度條了
mFrontPaint = new Paint();
mFrontPaint.setColor(roundProgressColor);
mFrontPaint.setAntiAlias(true);//消除鋸齒
mFrontPaint.setStyle(Paint.Style.STROKE);//空心圓
mFrontPaint.setStrokeWidth(roundWidth);
mFrontPaint.setAlpha(200);//透明度
//確定一個矩形的區域
RectF oval = new RectF(mXCenter-redis+roundWidth/2,mYCenter-redis+roundWidth/2,mXCenter+redis-roundWidth/2,mYCenter+redis-roundWidth/2);
progress = (int)((progress*1.0/maxProgress)*360);
/**
* 繪製扇形
* 第一個引數:確定的矩形區域
* 第二個引數:開始繪製的角度,從12點中開始繪製,角度為-90°
* 第三個引數:是否把弧形的2個點連線起來,false:不連線
* 第四個引數:畫筆
*/
canvas.drawArc(oval,-90,progress,false,mFrontPaint);
然後我們在MainActivity對應的xml檔案中新增自定義的CircleProgressView控制元件(此處的程式碼省略)。
我們在MainActivity中啟用一個執行緒來模擬下載,並結合Handle來處理模擬的結果
class MyThread extends Thread{
@Override
public void run() {
for (int i=0;i<100;i++){
Message msg = myHandler.obtainMessage();
msg.what = UPDATE_PROGRESS;
msg.obj = i+1;
myHandler.sendMessage(msg);
try {
Thread.sleep(100);//休眠100ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Handle接受到每次接受到訊息以後,呼叫CircleProgressView中的setProgress方法,設定進度的變化
private final int UPDATE_PROGRESS = 001;
CircleProgressView circleProgressView = null;
Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 001:
int progress =(int) msg.obj;
circleProgressView.setProgress(progress);
break;
}
}
};
那我們就要在CircleProgressView中給progress新增set,get方法,在set方法中,判斷當前的progress是否大於最大值,如果不大於,在重新繪製view
public void setProgress(int progress) {
this.progress = progress;
if(progress<=maxProgress){//判斷progress是否大於maxProgress
invalidate();//呼叫這個方法,會重新繪製
}
}
public int getProgress() {
return progress;
}
先看一下效果:
需要注意的是:這個時候關於圓形進度控制元件的屬性我們都是在程式碼中寫死的,這樣肯定不能達到複用的目的,我們需要把其中一些關鍵的屬性抽取出來,像系統控制元件的屬性那樣可以在xml中配置
在res/value檔案下新建一個attrs.xml的樣式檔案,定義以下屬性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RoundProgressBar">
<attr name="roundColor" format="color"/> <!-- 背景色-->
<attr name="roundProgressColor" format="color"/><!-- 進度條的顏色-->
<attr name="roundWidth" format="dimension"></attr><!-- 進度條的寬度-->
<attr name="textColor" format="color" /><!-- 字型的顏色-->
<attr name="textSize" format="dimension" /><!-- 字型的大小-->
</declare-styleable>
</resources>
然後我們在CircleProgressView的建構函式中獲取這些屬性,並且賦值。
自定義一個方法,initResource(attrs)獲取自定義的屬性值,並在建構函式中呼叫
private void initResource(AttributeSet attrs) {
//獲取我們自定義的檔名,RoundProgressBar是attrs中定義的name
TypedArray mTypeArray = mContext.obtainStyledAttributes(attrs,R.styleable.RoundProgressBar,0,0);
//獲取背景色,如果沒有設定則使用預設
backProgressColor = mTypeArray.getColor(R.styleable.RoundProgressBar_roundColor,backProgressColor);
//獲取進度條顏色,如果沒有設定則使用預設
roundProgressColor = mTypeArray.getColor(R.styleable.RoundProgressBar_roundProgressColor,roundProgressColor);
//獲取背景圓的半徑,如果沒有設定則使用預設
redis = mTypeArray.getDimension(R.styleable.RoundProgressBar_roundWidth,redis);
//進度條的寬度設定為半徑的1/5
roundWidth = redis/5;
//獲取文字的顏色,如果沒有設定則使用預設
textColor = mTypeArray.getColor(R.styleable.RoundProgressBar_textColor,textColor);
//獲取文字的大小,如果沒有設定則使用預設
textSize = mTypeArray.getDimension(R.styleable.RoundProgressBar_textSize,textSize);
}
然後我們重寫onMeasure()方法,測量控制元件的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getRealSize(widthMeasureSpec);
mHeight = getRealSize(heightMeasureSpec);
}
自定義一個getRealSize()的方法,得到控制元件的大小
private int getRealSize(int measureSpec){
float res = -1;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
if(mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED){
res = redis*2;
}else{
res = size;
}
return (int)res;
}
到此程式碼寫的已經差不多了。這兒需要注意:
在eclipse中使用自定義屬性,我們要加上
xmlns:app="http://schemas.android.com/apk/res/我們自己定義的view的包名"但是在Android studio中使用的時候這麼寫會報錯,提示找不到,我們直接讓它自動搜尋,需要這麼寫
xmlns:app ="http://schemas.android.com/apk/res-auto"
最後就是在xml中對自定義屬性的使用了
<main.zhaocd.com.circleprogressview.CircleProgressView
android:id="@+id/my_view"
android:layout_width="600dp"
android:layout_height="600dp"
app:roundWidth="80dp"
app:roundColor="#7f8d9c"
app:roundProgressColor="#07ce7e"
app:textColor="#e21e17"
app:textSize="40dp"
/>
最後在總結一下,一般自定義view的步驟:
1、建立attrs檔案,自定義屬性(如果一開始不能很好的把握需要那些屬性,可以把這一步放到最後)
2、在構造方法中獲取自定義的屬性
3、重寫onMeasure()方法(測量控制元件的大小)
4、重寫onDraw()方法(具體的繪製,呼叫invalidate()方法會強制執行onDraw方法)