相关视频:
本文参照以上视频进行编码!
效果图:
一、自定义属性设置:
<!--- 自定义进度条 //-->
<!--属性声明-->
<attr name="progress_unreach_color" format="color" />
<attr name="progress_unreach_height" format="dimension" />
<attr name="progress_reach_color" format="color" />
<attr name="progress_reach_height" format="dimension" />
<attr name="progress_text_color" format="color" />
<attr name="progress_text_size" format="dimension" />
<attr name="progress_text_offset" format="dimension" />
<!--属性使用-->
<declare-styleable name="PhHorizontalProgressBar">
<attr name="progress_unreach_color" />
<attr name="progress_unreach_height" />
<attr name="progress_reach_color" />
<attr name="progress_reach_height" />
<attr name="progress_text_color" />
<attr name="progress_text_size" />
<attr name="progress_text_offset" />
</declare-styleable>
<!--属性使用-->
<declare-styleable name="PhRoundProgressBar">
<attr name="radius" format="dimension" />
</declare-styleable>
<!--- 自定义进度条 //-->
二、自定义View:
PhHorizontalProgressBar.java
public class PhHorizontalProgressBar extends ProgressBar {
private static final int DEFAULT_TEXT_SIZE = 10;//sp
private static final int DEFAULT_TEXT_COLOR = 0xFFFC00D1;
private static final int DEFAULT_COLOR_UNREACH = 0xFFFC00D1;
private static final int DEFAULT_HEIGHT_UNREACH = 2;//dp
private static final int DEFAULT_COLOR_REACH = DEFAULT_TEXT_COLOR;
private static final int DEFAULT_HEIGHT_REACH = 2;//dp
private static final int DEFAULT_TEXT_OFFSET = 10;//dp
protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
protected int mTextColor = DEFAULT_TEXT_COLOR;
protected int mUnreachColor = DEFAULT_COLOR_UNREACH;
protected int mUnreachHeight = dp2px(DEFAULT_HEIGHT_UNREACH);
protected int mReachColor = DEFAULT_COLOR_REACH;
protected int mReachHeight = dp2px(DEFAULT_HEIGHT_REACH);
protected int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);
protected Paint mPaint = new Paint();
private int mRealWidth;
public PhHorizontalProgressBar(Context context) {
this(context, null);
}
public PhHorizontalProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PhHorizontalProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainStyledAttrs(attrs);
}
/**
* 获取自定义属性
*
* @param attrs
*/
private void obtainStyledAttrs(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs,
R.styleable.PhHorizontalProgressBar);
mTextSize = (int) typedArray.getDimension(
R.styleable.PhHorizontalProgressBar_progress_text_size, mTextSize);
mTextColor = typedArray.getColor(
R.styleable.PhHorizontalProgressBar_progress_text_color, mTextColor);
mTextOffset = (int) typedArray.getDimension(
R.styleable.PhHorizontalProgressBar_progress_text_offset, mTextOffset);
mUnreachColor = typedArray.getColor(
R.styleable.PhHorizontalProgressBar_progress_unreach_color, mUnreachColor);
mUnreachHeight = (int) typedArray.getDimension(
R.styleable.PhHorizontalProgressBar_progress_unreach_height, mUnreachHeight);
mReachColor = typedArray.getColor(
R.styleable.PhHorizontalProgressBar_progress_reach_color, mReachColor);
mReachHeight = (int) typedArray.getDimension(
R.styleable.PhHorizontalProgressBar_progress_reach_height, mReachHeight);
typedArray.recycle();
mPaint.setTextSize(mTextSize);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//在本案例中,由于是水平进度条,用户一定会给又给精确值来设置水平进度条的宽度,所以不用考虑宽度的mode
// int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
//实际绘制的区域宽度
mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
}
private int measureHeight(int heightMeasureSpec) {
int result = 0;
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
//需要自己测量高度,而高度是由reach高度、unreach高度和字体高度三者的最大值决定的
int textHeight = (int) (mPaint.descent() - mPaint.ascent());
result = getPaddingTop() + getPaddingBottom() +
Math.max(
Math.max(mReachHeight, mUnreachHeight),
Math.abs(textHeight));
if (mode == MeasureSpec.AT_MOST) {
//测量值不能超过给定的size值
result = Math.min(result, size);
}
}
return result;
}
@Override
protected synchronized void onDraw(Canvas canvas) {
//不需要这个,我们要完全自己控制draw的过程,所以可以注释掉或者删除
//super.onDraw(canvas);
canvas.save();
//画布移动到的位置
canvas.translate(getPaddingLeft(), getHeight() / 2);
//是否需要绘制unreachBar,若干reachBar和文本的宽度大于progressBar(即进度条已经达到100%,
// 就不需要绘制unreachBar了)
boolean noNeedUnreach = false;
// draw reach bar
String text = getProgress() + "%";
int textWidth = (int) mPaint.measureText(text);
float radio = getProgress() * 1.0f / getMax();
float progressX = radio * mRealWidth;
if (progressX + textWidth > mRealWidth) {
progressX = mRealWidth - textWidth;
noNeedUnreach = true;
}
float endX = progressX - mTextOffset / 2;
if (endX > 0) {
mPaint.setColor(mReachColor);
mPaint.setStrokeWidth(mReachHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
//draw text
mPaint.setColor(mTextColor);
int y = (int) (-(mPaint.descent() + mPaint.ascent()) / 2);
canvas.drawText(text, progressX, y, mPaint);
// draw unreach bar
if (!noNeedUnreach) {
float start = progressX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnreachColor);
mPaint.setStrokeWidth(mUnreachHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}
canvas.restore();
}
protected int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
getResources().getDisplayMetrics());
}
protected int sp2px(int spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal,
getResources().getDisplayMetrics());
}
}
PhRoundProgressBar .java
public class PhRoundProgressBar extends PhHorizontalProgressBar {
private int mRadius = dp2px(30);
private int mMaxPaintWidth;
public PhRoundProgressBar(Context context) {
this(context, null);
}
public PhRoundProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PhRoundProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//让ProgressBar变得更大
mReachHeight = (int) (mUnreachHeight * 2.5f);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PhRoundProgressBar);
mRadius = (int) typedArray.getDimension(R.styleable.PhRoundProgressBar_radius, mRadius);
typedArray.recycle();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
//设置连接处为弧形
mPaint.setStrokeCap(Paint.Cap.ROUND);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxPaintWidth = Math.max(mReachHeight, mUnreachHeight);
//默认四个padding一致
int expect = mRadius * 2 + getPaddingLeft() + getPaddingRight();
int width = resolveSize(expect, widthMeasureSpec);
int height = resolveSize(expect, heightMeasureSpec);
int realWidth = Math.min(width, height);
mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2;
setMeasuredDimension(realWidth, realWidth);
}
@Override
protected synchronized void onDraw(Canvas canvas) {
String text = getProgress() + "%";
float textWidth = mPaint.measureText(text);
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;
canvas.save();
canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2,
getPaddingRight() + mMaxPaintWidth / 2);
mPaint.setStyle(Paint.Style.STROKE);
//draw unreach bar
mPaint.setColor(mUnreachColor);
mPaint.setStrokeWidth(mUnreachHeight);
canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
//draw reach bar
mPaint.setColor(mReachColor);
mPaint.setStrokeWidth(mReachHeight);
float sweepAngle = getProgress() * 1.0f / getMax() * 360;
canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2),
0, sweepAngle, false, mPaint);
//draw text
mPaint.setColor(mTextColor);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight, mPaint);
canvas.restore();
}
}
三、使用:
xml中使用:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.gs.common3.activity.bView.customView.progress.PhHorizontalProgressBar
android:id="@+id/id_progress1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:progress="50"
android:padding="15dp"
app:progress_reach_color="#ffff0000"
app:progress_text_color="#ffff0000"
app:progress_unreach_color="#44ff0000"
/>
<com.gs.common3.activity.bView.customView.progress.PhHorizontalProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:progress="100"
android:padding="15dp"
app:progress_reach_color="#ffff0000"
app:progress_text_color="#ffff0000"
app:progress_unreach_color="#44ff0000"
/>
<com.gs.common3.activity.bView.customView.progress.PhHorizontalProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:progress="30"
android:padding="15dp"
app:progress_reach_color="#ffff0000"
app:progress_text_color="#ffff0000"
app:progress_unreach_color="#44ff0000"
/>
<com.gs.common3.activity.bView.customView.progress.PhRoundProgressBar
android:id="@+id/id_progress2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:progress="0"
android:padding="15dp"
app:radius="60dp"
app:progress_reach_color="#ffff0000"
app:progress_text_color="#ffff0000"
app:progress_unreach_color="#44ff0000"
/>
<com.gs.common3.activity.bView.customView.progress.PhRoundProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:progress="80"
android:padding="15dp"
app:radius="60dp"
app:progress_reach_color="#ffff0000"
app:progress_text_color="#ffff0000"
app:progress_unreach_color="#44ff0000"
/>
</LinearLayout>
</ScrollView>
public class CustomViewTest1Activity extends AppCompatActivity {
@BindView(R.id.id_progress1)
PhHorizontalProgressBar idProgress1;
@BindView(R.id.id_progress2)
PhRoundProgressBar idProgress2;
private static final int MSG_UPDATE = 0x110;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int progress = idProgress1.getProgress();
idProgress1.setProgress(++progress);
idProgress2.setProgress(++progress);
if (progress >= 100) {
mHandler.removeMessages(MSG_UPDATE);
}
mHandler.sendEmptyMessageDelayed(MSG_UPDATE, 100);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_view_test1);
ButterKnife.bind(this);
mHandler.sendEmptyMessage(MSG_UPDATE);
}
}