自定义View之炫丽的进度条

来源:互联网 发布:gettemppath linux 编辑:程序博客网 时间:2024/04/25 16:30

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

2 0