在项目开发中都会涉及到网络加载,文件上传或者下载,都会用到显示当前加载进度的进度条效果,最近刚好学了下自定义进度条,效果如下:
上面效果的实现还是通过自定义view,通过onMeasure()方法测量,onDraw()方法绘制实现的,一共涉及到三个东西的绘制,内圆(蓝色圆)、外圆(黄色圆)、中间文字的绘制,绘制完这些就可以实现大致效果了;不过还是跟之前几篇自定view播客一样,在绘制之前需要初始化自定义属性和画笔;
初始化定义属性:
//初始化属性
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProgressBar);
mInnerBackground = array.getColor(R.styleable.ProgressBar_innerBackground, mInnerBackground);
mOutterBackground = array.getColor(R.styleable.ProgressBar_outterBackground, mOutterBackground);
mProgressTextColor = array.getColor(R.styleable.ProgressBar_progressTextColor, mProgressTextColor);
mProgressTextSize = array.getDimensionPixelSize(R.styleable.ProgressBar_progressTextSize, sp2px(mProgressTextSize));
mRoundWidth = (int) array.getDimension(R.styleable.ProgressBar_roundWidth, dip2px(mRoundWidth));
array.recycle();
初始化画笔:
/**
* 根据绘制的颜色获取画笔
* @param color
*/
private Paint getPaint(int color){
Paint paint=new Paint();
paint.setAntiAlias(true);
paint.setColor(color);
paint.setStrokeWidth(mRoundWidth);
paint.setStyle(Paint.Style.STROKE);
return paint;
}
初始化完成后,就在onMeasure()方法中进行测量;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//宽高不一致时区最小值
width = Math.min(width, height);
height = Math.min(width, height);
setMeasuredDimension(width, height);
}
为了保证宽高一致使用Math.min(width, height)方法取最小值,这里直接用三元运算符也可以,其实Math.min(width, height)方法也是用的是三元运算符进行计算的;
Math.min(width, height)方法源码:
* @param a an argument.
* @param b another argument.
* @return the smaller of {@code a} and {@code b}.
*/
public static int min(int a, int b) {
return (a <= b) ? a : b;
}
接下来进行绘制:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int center = getWidth() / 2;
//先绘制内圆
canvas.drawCircle(center, center, center - mRoundWidth / 2, mInnerPaint);
//绘制外圆 画圆弧
if (mMax == 0) {
return;
}
RectF rectf = new RectF(0 + mRoundWidth / 2, 0 + mRoundWidth / 2, getWidth() - mRoundWidth / 2, getHeight() - mRoundWidth / 2);
float preProgree = (float) mCurrentProgress / mMax;
canvas.drawArc(rectf, 0, preProgree * 360, false, mOutterPaint);
//绘制进度文字
String text = ((int)(preProgree * 100)) + "%";
Rect rect = new Rect();
textPaint.getTextBounds(text, 0, text.length(), rect);
int x = getWidth() / 2 - rect.width() / 2;
Paint.FontMetricsInt metricsInt = textPaint.getFontMetricsInt();
int dy = (metricsInt.bottom - metricsInt.top) / 2 - metricsInt.bottom;
int baseLine = getHeight() / 2 + dy;
canvas.drawText(text, x, baseLine, textPaint);
}
绘制外圆的时候需要注意,外圆调用的不是canvas.drawCircle()方法,而是调用canvas.drawArc()绘制圆弧的方法进行绘制,这样效果就绘制完成了;接着又简单实现了下仿58的一个数据加载的效果;
这里就只实现了圆,正方形,正三角的一个切换效果,这个效果也是采用绘制实现的;在绘制的时候要定义一个变量用来表明当前绘制的是哪个图形;
public enum Shape {
Circle, Square, Triangle
}
这里用枚举来控制当前应该绘制哪个图形;同时在绘制完一个图形后还要改变当前的这个状态值;比如,绘制完圆,就要将状态改成正方形,绘制完正方形,就要将状态改成正三角,一直这样循环的去绘制;
/**
* 改变当前绘制的状态
*/
public void exchange() {
switch (mCurrentShape) {
case Circle:
mCurrentShape = Shape.Square;
break;
case Square:
mCurrentShape = Shape.Triangle;
break;
case Triangle:
mCurrentShape = Shape.Circle;
break;
}
//进行绘制
invalidate();
}
调用invalidate();最终就会去调用onDraw();方法进行绘制;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (mCurrentShape) {
case Circle:
//画圆形
int center = getWidth() / 2;
mPaint.setColor(mCircleColor);
canvas.drawCircle(center, center, center, mPaint);
break;
case Square:
//画正方形
mPaint.setColor(mSquareColor);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
break;
case Triangle:
//画三角形 绘制路线
mPaint.setColor(mTriangleColor);
if (mPath == null) {
mPath = new Path();
mPath.moveTo(getWidth() / 2, 0);
mPath.lineTo(0, (float) (getWidth() / 2 * Math.sqrt(3)));
mPath.lineTo(getWidth(), (float) (getWidth() / 2 * Math.sqrt(3)));
// path.lineTo(getWidth()/2,0);
//将绘制的路径闭合
mPath.close();
}
canvas.drawPath(mPath, mPaint);
break;
}
}
绘制圆或者正方形的时候调用相应的方法就可以进行绘制了,对于三角形的绘制并没有提供相应的方法,就要采用绘制路线的方式进行绘制,
从A点绘制到B点,从B点绘制到C点,从C点绘制到A点就可以了;从C点绘制到A点的时候,不采用这种方式也可以,从B点绘制到C点后直接调用mPath.close();方法将绘制路线闭合就可以了;因为要绘制的是等边三角形,在绘制的时候就要注意高度并不是getHeight();了,这里就要用到正弦这些东西来计算了,绘制的宽度是知道的,还是getWidth(),角度也知道,计算出高度就可以绘制了,绘制完成后,运行下就可以了。
源码地址: http://pan.baidu.com/s/1i587fnv