先看效果图:
酷炫进度条
1.自定义View分析
- 自定义属性的声明与获取
- 测量onMeasure
- 布局onLayout(ViewGroup)
- 绘制onDraw
- onTouchEvent
- onInterceptTouchEvent(ViewGroup)
- 状态的恢复和保存
2.自定义属性的声明与获取
2.1分析需要的自定义属性
2.2在res/values/attrs.xml中定义声明
2.3在layout文件中进行使用
2.4在View的构造方法中进行获取
3.代码实现之水平进度条
3.1在values下新建attrs.xml文件,声明如下属性:
<attr name="progress_unreach_color" format="color"></attr>
<attr name="progress_unreach_height" format="dimension"></attr>
<attr name="progress_reach_color" format="color"></attr>
<attr name="progress_reach_height" format="dimension"></attr>
<attr name="progress_text_color" format="color"></attr>
<attr name="progress_text_size" format="dimension"></attr>
<attr name="progress_text_offset" format="dimension"></attr>
<!--使用属性,name是继承自ProgressBar的自定义View的名字-->
<declare-styleable name="NiceHorizontalProgressbarWithProgress">
<attr name="progress_unreach_color"></attr>
<attr name="progress_unreach_height"></attr>
<attr name="progress_reach_color"></attr>
<attr name="progress_reach_height"></attr>
<attr name="progress_text_color"></attr>
<attr name="progress_text_size"></attr>
<attr name="progress_text_offset"></attr>
</declare-styleable>
3.2代码中获取属性值
public class NiceHorizontalProgressbarWithProgress extends ProgressBar {
//默认的属性设置
private static final int DEFAULT_TEXT_SIZE = 10;//sp
private static final int DEFAULT_TEXT_COLOR = 0xFFC00D1;
private static final int DEFAULT_COLOR_UNREACH = 0xFFD3D6DA;
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
//转换数据
private int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
private int mTextColor = DEFAULT_TEXT_COLOR;
private int mUnReachColor = DEFAULT_COLOR_UNREACH;
private int mUnReachHeight = dp2px(DEFAULT_HEIGHT_UNREACH);
private int mReachColor = DEFAULT_COLOR_REACH;
private int mReachHeight = dp2px(DEFAULT_HEIGHT_REACH);
private int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);
//画笔
private Paint mPaint = new Paint();
private int mReachWidth;
//在代码中new控件时使用这个构造方法
public NiceHorizontalProgressbarWithProgress(Context context) {
this(context, null);
}
//布局文件中使用控件时使用这个构造方法,2个参数的调用三个参数的构造方法
public NiceHorizontalProgressbarWithProgress(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
//三个参数的构造方法
public NiceHorizontalProgressbarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取自定义的属性
obtainStyledAttrs(attrs);
}
//获取属性
private void obtainStyledAttrs(AttributeSet attributeSet) {
TypedArray ta = getContext().obtainStyledAttributes(attributeSet, R.styleable.NiceHorizontalProgressbarWithProgress);
mTextSize = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_text_size, mTextSize);
mTextColor = ta.getColor(R.styleable.NiceHorizontalProgressbarWithProgress_progress_text_color, mTextColor);
mTextOffset = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_text_offset, mTextOffset);
mUnReachColor = ta.getColor(R.styleable.NiceHorizontalProgressbarWithProgress_progress_unreach_color, mUnReachColor);
mUnReachHeight = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_unreach_height, mUnReachHeight);
mReachColor = ta.getColor(R.styleable.NiceHorizontalProgressbarWithProgress_progress_reach_color, mReachColor);
mReachHeight = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_reach_height, mReachHeight);
ta.recycle();
mPaint.setTextSize(mTextSize);
}
//不同单位的转换方法
private int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
}
private int sp2px(int spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, getResources().getDisplayMetrics());
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//测量宽度,默认用户会给定
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthVal = MeasureSpec.getSize(widthMeasureSpec);
//测量高度
int height = measureHeight(heightMeasureSpec);
//设定数据
setMeasuredDimension(widthVal, height);
//实际绘制的一个区域
mReachWidth = 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 {
int textHeight = (int) (mPaint.descent() - mPaint.ascent());
result = getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachHeight, mUnReachHeight), Math.abs(textHeight));
if (mode == MeasureSpec.AT_MOST) {
//不能超过用户给的最大值
result = Math.min(result, size);
}
}
return result;
}
@Override
protected synchronized void onDraw(Canvas canvas) {
//super.onDraw(canvas);
//自己绘制
canvas.save();
canvas.translate(getPaddingLeft(), getHeight() / 2);
boolean noNeedUnReach = false;
//draw reachbar
String text = getProgress() + "%";
int textWidth = (int) mPaint.measureText(text);
float radio = getProgress() * 1.0f / getMax();
float progressX = radio * mReachWidth;
if (progressX + textWidth > mReachWidth) {
progressX = mReachWidth - 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 unReachbar
if (!noNeedUnReach) {
float startx = progressX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachColor);
mPaint.setStrokeWidth(mUnReachHeight);
canvas.drawLine(startx, 0, mReachWidth, 0, mPaint);
}
canvas.restore();
}
}
3.3在布局文件中使用自定义的View(在根部局中加入:xmlns:app=”http://schemas.android.com/apk/res-auto”)
<com.example.administrator.niceprogressbar.NiceProgressbarWithProgress.NiceHorizontalProgressbarWithProgress
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:id="@+id/pb_01"
app:progress_reach_color="#ff0000"
app:progress_text_color="#000fff"
app:progress_text_size="16sp"
app:progress_unreach_color="#ffd320"
app:progress_reach_height="10dp">
<com.example.administrator.niceprogressbar.NiceProgressbarWithProgress.NiceHorizontalProgressbarWithProgress>
代码实现之圆形进度条(在水平进度条的基础之上)
4.1声明一个半径
<attr name="progress_radius" format="dimension" />
</declare-styleable>
4.2自定义View继承水平进度条,需要把一些private改变成protected
public class RoundProgressbar extends NiceHorizontalProgressbarWithProgress {
//圆的半径
private int mRadius = dp2px(30);
private int mMaxPaintWidth;
public RoundProgressbar(Context context) {
this(context, null);
}
public RoundProgressbar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressbar);
mRadius = (int) ta.getDimension(R.styleable.RoundProgressbar_progress_radius, mRadius);
ta.recycle();
mPaint.setStyle(Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStrokeCap(ROUND);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mMaxPaintWidth = Math.max(mReachHeight, mUnReachHeight);
int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight();
int width = resolveSize(expect, widthMeasureSpec);
int height = resolveSize(expect, heightMeasureSpec);
int readWidth = Math.max(width, height);
mRadius = (readWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2;
setMeasuredDimension(readWidth, readWidth);
}
@Override
protected synchronized void onDraw(Canvas canvas) {
//super.onDraw(canvas);
String text = getProgress() + "%";
float textWidth = mPaint.measureText(text);
float textHeight=(mPaint.descent()+mPaint.ascent())/2;
canvas.save();
canvas.translate(getPaddingLeft()+mMaxPaintWidth/2,getPaddingTop()+mMaxPaintWidth/2);
mPaint.setStyle(Style.STROKE);
//draw unReachBar
mPaint.setColor(mUnReachColor);
mPaint.setStrokeWidth(mUnReachHeight);
canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
//draw reachBar
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(Style.FILL);
canvas.drawText(text,mRadius-textWidth/2,mRadius-textHeight,mPaint);
canvas.restore();
}}

被折叠的 条评论
为什么被折叠?



