自定义View之炫丽的进度条

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zgkxzx/article/details/56691226

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

猜你喜欢

转载自blog.csdn.net/zgkxzx/article/details/56691226