带自定义属性的进度条
image.png前三个进度条基本是系统原生的,详情见我的上一篇文章自定义进度条之样式篇
今天我们讲一下下边的2个带文字的自定义进度条,如果对paint,canvas,bitmap.onDraw,onMeasure不太了解的同学,可以先看看自定义控件三部曲中的绘图篇
-
自定义属性
在res/values下新建文件attr_progress_bar.xml<declare-styleable name="HorizontalProgressBarWithNumber"> // 声名属性集的名称,即这些属性是属于哪个控件的。 <attr name="progress_unreached_color" format="color" /> //进度未达到颜色 <attr name="progress_reached_color" format="color" /> //进度已经达到的颜色 <attr name="progress_reached_bar_height" format="dimension" /> //进度条已经达到的高 <attr name="progress_unreached_bar_height" format="dimension" />//进度条未达到的高 <attr name="progress_text_size" format="dimension" /> //进度条文字的大小(SP) <attr name="progress_text_color" format="color" /> //进度条文字的颜色 <attr name="progress_text_offset" format="dimension" /> //进度条文字的偏移量 <attr name="progress_text_visibility" format="enum"> //进度条文字是否可见 <enum name="visible" value="0" /> //枚举值可见 <enum name="invisible" value="1" /> //枚举值不可见 </attr> </declare-styleable>
.简单说一下上边所使用的 <attr name="progress_unreached_color" format="color" />
- 其中name是我们给这个自定义属性所起的名称,
- format是自定义属性的类型,
Android一共给我们提供了八种自定义属性的类型,分别是:
Num | format | 类型 |
---|---|---|
1 | reference | 引用 |
2 | color | 颜色 |
3 | boolean | 布尔值 |
4 | dimension | 尺寸值 |
5 | float | 浮点值 |
6 | integer | 整型值 |
7 | string | 字符串 |
8 | enum | 枚举值 |
2.创建自定义进度条的HorizontalProgressBarWithNumber类继承与ProgressBar
package com.xvdong.custom.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ProgressBar;
import com.xvdong.custom.R;
/**
* Created by xvDong on 2018/5/16.
*/
public class HorizontalProgressBarWithNumber extends ProgressBar {
private static final int DEFAULT_TEXT_SIZE = 10;
private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;
/**
* painter of all drawing things
*/
protected Paint mPaint = new Paint();
/**
* color of progress number
*/
protected int mTextColor = DEFAULT_TEXT_COLOR;
/**
* size of text (sp)
*/
protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
/**
* offset of draw progress
*/
protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);
/**
* height of reached progress bar
*/
protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/**
* color of reached bar
*/
protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
/**
* color of unreached bar
*/
protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
/**
* height of unreached progress bar
*/
protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/**
* view width except padding
*/
protected int mRealWidth;
protected boolean mIfDrawText = true;
protected static final int VISIBLE = 0;
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setHorizontalScrollBarEnabled(true);
obtainStyledAttributes(attrs);
mPaint.setTextSize(mTextSize);
mPaint.setColor(mTextColor);
}
/**
* get the styled attributes
*
* @param attrs
*/
private void obtainStyledAttributes(AttributeSet attrs) {
// init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(
attrs, R.styleable.HorizontalProgressBarWithNumber);
mTextColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
DEFAULT_TEXT_COLOR);
mTextSize = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_size,
mTextSize);
mReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
mTextColor);
mUnReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
mReachedProgressBarHeight);
mUnReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
mUnReachedProgressBarHeight);
mTextOffset = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,
mTextOffset);
int textVisible = attributes
.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
VISIBLE);
if (textVisible != VISIBLE) {
mIfDrawText = false;
}
attributes.recycle();
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
float textHeight = (mPaint.descent() + mPaint.ascent());
int exceptHeight = (int) (getPaddingTop() + getPaddingBottom() + Math
.max(Math.max(mReachedProgressBarHeight,
mUnReachedProgressBarHeight), Math.abs(textHeight)));
heightMeasureSpec = MeasureSpec.makeMeasureSpec(exceptHeight,
MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected synchronized void onDraw(Canvas canvas) {
canvas.save();
//画笔平移到指定paddingLeft, getHeight() / 2位置,注意以后坐标都为以此为0,0
canvas.translate(getPaddingLeft(), getHeight() / 2);
boolean noNeedBg = false;
//当前进度和总值的比例
float radio = getProgress() * 1.0f / getMax();
//已到达的宽度
float progressPosX = (int) (mRealWidth * radio);
//绘制的文本
String text = getProgress() + "%";
//拿到字体的宽度和高度3265
float textWidth = mPaint.measureText(text);
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;
//如果到达最后,则未到达的进度条不需要绘制
if (progressPosX + textWidth > mRealWidth) {
progressPosX = mRealWidth - textWidth;
noNeedBg = true;
}
// 绘制已到达的进度
float endX = progressPosX - mTextOffset / 2;
if (endX > 0) {
mPaint.setColor(mReachedBarColor);
mPaint.setStrokeWidth(mReachedProgressBarHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
// 绘制文本
if (mIfDrawText) {
mPaint.setColor(mTextColor);
canvas.drawText(text, progressPosX, -textHeight, mPaint);
}
// 绘制未到达的进度条
if (!noNeedBg) {
float start = progressPosX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}
canvas.restore();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRealWidth = w - getPaddingRight() - getPaddingLeft();
}
/**
* dp 2 px
*
* @param dpVal
*/
protected int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
/**
* sp 2 px
*
* @param spVal
* @return
*/
protected int sp2px(int spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, getResources().getDisplayMetrics());
}
}
-
自定义属性在layout.xml文件中的使用
声明命名空间.png
3.1 在使用之前必须声名命名空间:
xmlns:app="http://schemas.android.com/apk/res-auto"
这一步一般AndroidStudio会自动帮我们声明完成.
3.2 自定义属性在自定义控件上的使用:<com.xvdong.custom.view.HorizontalProgressBarWithNumber app:progress_reached_bar_height="20dp" app:progress_unreached_bar_height="30dp" app:progress_text_color="@color/colorPrimaryDark" app:progress_text_size="20dp" app:progress_reached_color="@color/colorPrimaryDark" app:progress_text_offset="10dp" app:progress_text_visibility="visible" app:progress_unreached_color="@color/colorAccent" android:padding="10dp" android:id="@+id/id_progressbar01" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="10dp" android:layout_marginStart="10dp" android:layout_marginTop="10dp"/>
-
自定义进度条的使用
private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { int progress = mProgressBar.getProgress(); mProgressBar.setProgress(++progress); if (progress >= 100) { mHandler.removeMessages(MSG_PROGRESS_UPDATE); } mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100); }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mProgressBar = findViewById(R.id.id_progressbar01); mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE); }
网友评论