github地址: https://github.com/w296365959/IndicateProgressBar
同事給的效果圖索要個這樣的進度條,趁着空閒時間,就做了這個
IndicateProgressBar ,這是一個簡單的自定義View,帶指示器的進度條。
如有 不足之處,盡情指出
轉載請標明出處:
http://blog.csdn.net/w296365959/article/details/78496985
效果圖:
整體思路:
先把底部背景條給畫出,就是一個帶圓角的矩形;
接着我們畫進度條,我們可以看到進度條也是一個帶圓角的矩形,同理,我們一樣只要畫出一個帶圓角的矩形就可以了,只不過這個矩形長度是可以變化的而已,矩形左邊x座標爲0,右邊x座標是背景條長度*進度比例, 我們進度條顏色是隨着進度改變而漸變的,這也簡單,可以直接使用Shader 來設置漸變色。這樣進度畫好了;
接着,畫進度條的指示器,指示器室友3部分組成的,一個外框+內部填充+一個進度文本,
這都是一樣 ,畫個矩形就可以了,只不過給畫筆顏色不同,最後在畫一個文本,這文本寫在矩形框內,具體數據可以自己調試。
關鍵代碼分析:
//在ondraw裏面畫出進度條背景,進度,以及指示器
width = getWidth() - (int) (indicateTextPaint.measureText(max + "%") + defaultMargin);//進度條最大寬度,減去文本長度+defaultMargin 是爲了放置指示器位置,
height = getHeight();
//畫背景
RectF backRectF = new RectF(0, height * 2 / 5, width, height * 3 / 5);
canvas.drawRoundRect(backRectF, radius, radius, backPaint);
//畫進度
RectF progressRectF = new RectF(0, height * 2 / 5, width * getScale(), height * 3 / 5);
Shader shader = new LinearGradient(0, 0, 400, 400, startProgressColor, Color.RED, Shader.TileMode.REPEAT);//漸變
progressPaint.setShader(shader);
canvas.drawRoundRect(progressRectF, radius, radius, progressPaint);
//畫指示器邊框
float left = getScale() * width;
float right = getScale() * width + indicateTextPaint.measureText(max + "%") + defaultMargin;
if (left <= 0f) {//當指示器最左邊不在控件範圍時,強制左邊界=0
left = 0f;
right = indicateTextPaint.measureText(max + "%") + defaultMargin;
}
if (left >= width) {//當指示器左邊界超出控件範圍時,強制左邊界=進度最大長度
left = width;
right = width + indicateTextPaint.measureText(max + "%") + defaultMargin;
}
RectF indicatorRectF = new RectF(left, height / 5, right, height * 4 / 5);
indicateBackPaint.setColor(textColor);
canvas.drawRoundRect(indicatorRectF, indicatorRadius, indicatorRadius, indicateBackPaint);
//畫指示器內部爲白色
RectF indicatorContentRectF = new RectF(left + 2, height / 5 + 2, right - 2, height * 4 / 5 - 2);
indicateBackPaint.setColor(Color.WHITE);
canvas.drawRoundRect(indicatorContentRectF, indicatorRadius, indicatorRadius, indicateBackPaint);
//畫指示器文本
float textX = indicatorContentRectF.centerX() - indicateTextPaint.measureText(progressText) / 2;
float textY = backRectF.centerY() + height / 9;
canvas.drawText(progressText, textX, textY, indicateTextPaint);
然後,在onTouchEvent裏控制 手指拖動進度條,isCanTouch可以控制是否可以拖動
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isCanTouch) {//開啓可手動拖動
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
x = event.getX();//基於控件的座標
/*float rawX = event.getRawX();//基於屏幕的座標
Log.i(TAG, "x==: " + x);
Log.i(TAG, "rawX==: " + rawX);
Log.i(TAG, "width==: " + width);
Log.i(TAG, "height==: " + height);*/
int count = (int) x * 100 / width;
if (count > 100) {
count = 100;
} else if (count < 0) {
count = 0;
}
progressText = count + "%";
setProgress(count);
Log.i(TAG, "progressText==: " + progressText);
invalidate();//主線程中調用刷新
// postInvalidate();//可在非UI線程中調用刷新,底層還是使用handler發送到主線程刷新重繪
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}else {
return super.onTouchEvent(event);
}
}
代碼簡單易懂,完整代碼如下:
/**
* Author: wangzhongming<br/>
* Date : 2017/11/8 11:33 </br>
* Summary: 帶指示器的進度條
*/
public class IndicateProgressBar extends View {
private float x = 10;
private String progressText = "0%";
private static final String TAG = IndicateProgressBar.class.getSimpleName();
private int width;
private int height;
private Paint backPaint;
private Paint progressPaint;
private Paint indicateTextPaint;
private Paint indicateBackPaint;
private int radius = 10; //進度條四個角的角度px
private int indicatorRadius = 32; //進度指示器四個角的角度px
private int defaultMargin = 30; //進度指示器默認多一點長度
private int max = 100;//進度最大值
private int progress = 0;//進度0-100
private boolean isCanTouch = true;//進度條是否可以手動拖動
private int startProgressColor = 0xfff29310;
private int textColor = 0xffef4f37;
private int gray = 0xfff5f5f5;
public IndicateProgressBar(Context context) {
this(context, null);
}
public IndicateProgressBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
// Android在用畫筆的時候有三種Style,分別是
// Paint.Style.STROKE 只繪製圖形輪廓(描邊)//空心效果
// Paint.Style.FILL 只繪製圖形內容
// Paint.Style.FILL_AND_STROKE 既繪製輪廓也繪製內容
//Paint.ANTI_ALIAS_FLAG 抗鋸齒
//進度條背景畫筆
backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
backPaint.setColor(gray);
backPaint.setStyle(Paint.Style.FILL_AND_STROKE);
//進度條進度畫筆
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressPaint.setStyle(Paint.Style.FILL);
//進度條指示器框畫筆
indicateBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
indicateBackPaint.setColor(textColor);
indicateBackPaint.setTextSize(32);
//進度條指示器文本畫筆
indicateTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
indicateTextPaint.setColor(textColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
width = getWidth() - (int) (indicateTextPaint.measureText(max + "%") + defaultMargin);
height = getHeight();
//畫背景
RectF backRectF = new RectF(0, height * 2 / 5, width, height * 3 / 5);
canvas.drawRoundRect(backRectF, radius, radius, backPaint);
//畫進度
RectF progressRectF = new RectF(0, height * 2 / 5, width * getScale(), height * 3 / 5);
Shader shader = new LinearGradient(0, 0, 400, 400, startProgressColor, Color.RED, Shader.TileMode.REPEAT);//漸變
progressPaint.setShader(shader);
canvas.drawRoundRect(progressRectF, radius, radius, progressPaint);
//畫指示器邊框
float left = getScale() * width;
float right = getScale() * width + indicateTextPaint.measureText(max + "%") + defaultMargin;
if (left <= 0f) {
left = 0f;
right = indicateTextPaint.measureText(max + "%") + defaultMargin;
}
if (left >= width) {
left = width;
right = width + indicateTextPaint.measureText(max + "%") + defaultMargin;
}
RectF indicatorRectF = new RectF(left, height / 5, right, height * 4 / 5);
indicateBackPaint.setColor(textColor);
canvas.drawRoundRect(indicatorRectF, indicatorRadius, indicatorRadius, indicateBackPaint);
//畫指示器內部爲白色
RectF indicatorContentRectF = new RectF(left + 2, height / 5 + 2, right - 2, height * 4 / 5 - 2);
indicateBackPaint.setColor(Color.WHITE);
canvas.drawRoundRect(indicatorContentRectF, indicatorRadius, indicatorRadius, indicateBackPaint);
//畫指示器文本
float textX = indicatorContentRectF.centerX() - indicateTextPaint.measureText(progressText) / 2;
float textY = backRectF.centerY() + height / 9;
canvas.drawText(progressText, textX, textY, indicateTextPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isCanTouch) {//開啓可手動拖動
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
x = event.getX();//基於控件的座標
/*float rawX = event.getRawX();//基於屏幕的座標
Log.i(TAG, "x==: " + x);
Log.i(TAG, "rawX==: " + rawX);
Log.i(TAG, "width==: " + width);
Log.i(TAG, "height==: " + height);*/
int count = (int) x * 100 / width;
if (count > 100) {
count = 100;
} else if (count < 0) {
count = 0;
}
progressText = count + "%";
setProgress(count);
Log.i(TAG, "progressText==: " + progressText);
invalidate();//主線程中調用刷新
// postInvalidate();//可在非UI線程中調用刷新,底層還是使用handler發送到主線程刷新重繪
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}else {
return super.onTouchEvent(event);
}
}
/**
* 是否開啓拖動有效
* 默認可以手動拖動
*
* @param isOpen true開啓可以手動拖動
*/
public void setCanTouch(boolean isOpen) {
isCanTouch = isOpen;
}
/**
* 設置進度,getScale()內會調用
*
* @param progress 0-100 ,最大進度默認100
*/
public void setProgress(int progress) {
this.progress = progress;
}
/**
* 設置進度,getScale()內會調用
*
* @param progress 進度 0-100
* @param max 最大進度 ,不寫則默認100
*/
public void setProgress(int progress, int max) {
this.progress = progress;
this.max = max;
}
/**
* 進度顯示百分數
*
* @param strText 如寫 70%
*/
private void setProgeressText(String strText) {
progressText = strText;
}
/**
* 進度比例小數
*
* @return
*/
private float getScale() {
float scale;
if (max == 0) {
scale = 0;
} else {
scale = (float) progress / (float) max;
}
setProgeressText((int) (scale * 100) + "%");
return scale;
}
}
好了,一個簡單的帶指示器的進度條完成了!