Android自定义View之炫丽的进度条
好久没有写Blog了,昨天意外看到自己无意中写的一篇文章,访问量都有1k+,突然之间觉得写博客,分享知识是一件多么幸福的事情!今天我给大家分享一个自定义view来绘制一个项目中经常用的炫丽立体效果的进度条.虽然不怎么有难度,但是项目中经常用到,希望能帮助大家项目中的一些问题,帮到大家。
代码下载地址:http://download.csdn.net/detail/zgkxzx/9762403
实现原理
主要是通过Paint的setXfermode(Xfermode xfermode) 图像混合模式,关于paint的混合模式的知识,小编就不在这里科普了,自己到百度上面谷歌一下就知道了。下面我们找重点的地方讲解。如下,多种混合模式的效果图:
这里,我们用的的模式是SRC_IN,从效果图中,我们很清晰看出,当SRC是蓝色正方形图片,DST为橙色圆形图片时,SRC_IN效果,即为当SRC与DST重叠发生,交集部分为两图交集区域,并展现出SRC交集区域。这里,我们项目中SRC为
DST资源为通过画布画的扇形图像,由于图片源SRC是一张切图,我们不容易控制进度,那么我们通过控制扇形的区域,来实现整体画布的进度条的控制。如下图,没有找到比较好的作图工具,自己用Galaxy Note机手绘图形进行分析(画的不好,不要吐槽~~)。
当DST扇形(红色区域)在画布上扫过,与SRC的交集部分,即画布上面最终展现的区域(紫色区域),这里的扇形起始边是-270度。我们可以根据实际需要进行调整。好了,我们不多说了,直接上源码分析。
代码实现
自定义View的步骤一般是onMeasure,onLayout,onDraw,这里我们只需要测量和绘制就行了。
第一步:初始化参数
//背景图片和进度条图片
private Bitmap bgBmp;
private Bitmap bgProcess;
private PorterDuffXfermode mMode;
private Paint mXferPaint;
private RectF mOval;
private Paint mTextPaint;
//百分比
private int mPercent;
//边长
private int sideLength;
//缩放比例
private float scale = 1.0f;
private void init() {
bgBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ring_bg);
if (processImg != null) {
bgProcess = ((BitmapDrawable) processImg).getBitmap();
} else
bgProcess = BitmapFactory.decodeResource(getResources(), R.mipmap.ring_bg_1);
mMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
mXferPaint = new Paint();
mXferPaint.setColor(Color.GREEN);
mXferPaint.setXfermode(mMode);
mXferPaint.setAntiAlias(true);
mOval = new RectF();
mOval.left = 0;
mOval.top = 0;
mPercent = 0;
mTextPaint = new Paint();
mTextPaint.setColor(textColor);
mTextPaint.setTextSize(textSize);
mTextPaint.setAntiAlias(true);
Typeface font = Typeface.createFromAsset(context.getAssets(), textFont != null ? textFont : DEFAULR_FONT);
mTextPaint.setTypeface(font);
}
在初始化中,主要是对需要绘画的几个画笔进行了初始化。这里比较重要的是我们用的的PorterDuffXfermode混合图像模式,在这里采用了SRC_IN模式。画笔画出的扇形和原始进度条图片发生交集后,显示原始进度条图片的部分。在设计进度条之前,小编考虑到可扩展性,本来是准备采用DST_IN模式,这样进度条显示部分为交集的扇形部分,这样进度条的颜色通过xml倒是很方便配置,但是进度条通过drawArc方法画出来的是屏幕效果图,效果没有切片能展现立体的效果。
第二步:onMeasure方法实现测量
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
int bgWidth = bgBmp.getWidth();
int bgHight = bgBmp.getHeight();
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = bgWidth;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = bgHight;
}
//得到边长,这里默认进度条为正方形的控件
sideLength = Math.min(width, height);
//计算比例缩放系数
scale = (float) sideLength / bgWidth;
setMeasuredDimension(sideLength, sideLength);
在测量部分,如果采用包裹方式,控件的大小为原切片背景大大小;如果EXACTLY方式,那么原切片货更加精确的长宽进行比例缩放。
第三步:关键部分onDraw方法的实现
//矩阵运算 主要是根据xml的设置对原切片进行比例缩放
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
mXferPaint.setXfermode(null);
canvas.drawBitmap(bgBmp, matrix, mXferPaint);
//将绘制操作保存到新的图层(离屏缓存)
int saveCount = canvas.saveLayer(0, 0, sideLength, sideLength, null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
mOval.left = 0;
mOval.top = 0;
mOval.right = sideLength;
mOval.bottom = sideLength;
mXferPaint.setXfermode(null);
//绘制扇形区域,关于-235,290这个角度,根据实际切片的角度填写,找美工妹子要就行了~~~
canvas.drawArc(mOval, -235, 290 * mPercent / MAX_PROCESS, true, mXferPaint);
mXferPaint.setXfermode(mMode);
canvas.drawBitmap(bgProcess, matrix, mXferPaint);
//绘制进度字
String text = mPercent + "";
canvas.drawText(text, 0, text.length(),
sideLength / 2 - ViewUtil.getTextWidth(mTextPaint, text) / 2,
sideLength / 2 + ViewUtil.getTextHeight(mTextPaint, text) / 2,
mTextPaint);
canvas.restoreToCount(saveCount);
至此,代码部分也说完了,此自定义view并不怎么复杂,但是工程中经常用到,希望能帮到大家,一起学习进步…
本来是准备代码在Github和csdn各上传一份便于大家参考,可惜最近Github连接不上去了。
代码下载地址:http://download.csdn.net/detail/zgkxzx/9762403