• Android 自定义View修炼-高仿猎豹清理大师自定义内存开口圆环比例进度View


    一、概述

    看见猎豹清理大师的内存开口圆环比例进度 挺有意思的,于是就是想自己实现下这样的效果,于是反编译了猎豹清理

    大师的app看了下,原来是有两张图,于是脑子里就过了下思路,利用上下两张图,旋转上面张图以及使用

    PorterDuffXfermode  来设置合适的渲染模式,就可以达到效果。下面看看咱们的效果吧

    二、效果图

    三、Xfermode渲染模式简介:

    xfermode影响在Canvas已经有的图像上绘制新的颜色的方式 
    * 正常的情况下,在图像上绘制新的形状,如果新的Paint不是透明的,那么会遮挡下面的颜色. 
    * 如果新的Paint是透明的,那么会被染成下面的颜色 

    下面的Xfermode子类可以改变这种行为: 

    AvoidXfermode  指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。 

    PixelXorXfermode  当覆盖已有的颜色时,应用一个简单的像素XOR操作。 

    PorterDuffXfermode  这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。

    这里不得不提到那个经典的图:

    上面的16种模式的说明如下:

    从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:

    1.PorterDuff.Mode.CLEAR  

      所绘制不会提交到画布上。
    2.PorterDuff.Mode.SRC

       显示上层绘制图片
    3.PorterDuff.Mode.DST

      显示下层绘制图片
    4.PorterDuff.Mode.SRC_OVER

      正常绘制显示,上下层绘制叠盖。
    5.PorterDuff.Mode.DST_OVER

      上下层都显示。下层居上显示。
    6.PorterDuff.Mode.SRC_IN

       取两层绘制交集。显示上层。
    7.PorterDuff.Mode.DST_IN

      取两层绘制交集。显示下层。
    8.PorterDuff.Mode.SRC_OUT

     取上层绘制非交集部分。
    9.PorterDuff.Mode.DST_OUT

     取下层绘制非交集部分。
    10.PorterDuff.Mode.SRC_ATOP

     取下层非交集部分与上层交集部分
    11.PorterDuff.Mode.DST_ATOP

     取上层非交集部分与下层交集部分
    12.PorterDuff.Mode.XOR

      异或:去除两图层交集部分
    13.PorterDuff.Mode.DARKEN

      取两图层全部区域,交集部分颜色加深
    14.PorterDuff.Mode.LIGHTEN

      取两图层全部,点亮交集部分颜色
    15.PorterDuff.Mode.MULTIPLY

      取两图层交集部分叠加后颜色
    16.PorterDuff.Mode.SCREEN

      取两图层全部区域,交集部分变为透明色

    四、自定义开口圆环View的实现

    1、初始化绘制所需的画笔,字体颜色、大小等变量

    public XCArcProgressBar(Context context, AttributeSet attrs,
                int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            // TODO Auto-generated constructor stub
            
            
            degrees =  0;
            paint  =  new Paint();
            //从attrs.xml中获取自定义属性和默认值
            TypedArray typedArray  = context.obtainStyledAttributes(attrs, R.styleable.XCRoundProgressBar);
            textColor  =typedArray.getColor(R.styleable.XCRoundProgressBar_textColor, Color.RED);
            textSize = typedArray.getDimension(R.styleable.XCRoundProgressBar_textSize, 15);
            max = typedArray.getInteger(R.styleable.XCRoundProgressBar_max, 100);
            isDisplayText  =typedArray.getBoolean(R.styleable.XCRoundProgressBar_textIsDisplayable, true);
            typedArray.recycle();
            
        }

    2、在onDraw()中绘制出来

    在onDraw()方法中利用PorterDuffXfermode渲染模式绘制两张开口圆环Bitmap,并计算前景图的旋转角度,从而达到效果图效果。

    首先先绘制底部背景图,然后绘制进度前景图,最后利用PorterDuffXfermode的渲染模式和旋转角度比例来进行前景图和背景图的遮罩处理。

    @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);
            int width = getWidth();
            int height = getHeight();
            int centerX = getWidth() / 2;// 获取中心点X坐标
            int centerY = getHeight() / 2;// 获取中心点Y坐标
    
            Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
            Canvas can = new Canvas(bitmap);
            // 绘制底部背景图
            bmpTemp = Utils.decodeCustomRes(getContext(), R.drawable.arc_bg);
            float dstWidth = (float) width;
            float dstHeight = (float) height;
            int srcWidth = bmpTemp.getWidth();
            int srcHeight = bmpTemp.getHeight();
    
            can.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
                    | Paint.FILTER_BITMAP_FLAG));// 抗锯齿
    
            Bitmap bmpBg = Bitmap.createScaledBitmap(bmpTemp, width, height, true);
            can.drawBitmap(bmpBg, 0, 0, null);
    
            // 绘制进度前景图
            Matrix matrixProgress = new Matrix();
            matrixProgress.postScale(dstWidth / srcWidth, dstHeight / srcWidth);
            bmpTemp = Utils.decodeCustomRes(getContext(), R.drawable.arc_progress);
    
            Bitmap bmpProgress = Bitmap.createBitmap(bmpTemp, 0, 0, srcWidth,
                    srcHeight, matrixProgress, true);
            degrees = progress * 270 / max - 270;
            //遮罩处理前景图和背景图
            can.save();
            can.rotate(degrees, centerX, centerY);
            paint.setAntiAlias(true);
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
            can.drawBitmap(bmpProgress, 0, 0, paint);
            can.restore();
            
            if ((-degrees) >= 85) {
                int posX = 0;
                int posY = 0;
                if ((-degrees) >= 270) {
                    posX = 0;
                    posY = 0;
                } else if ((-degrees) >= 225) {
                    posX = centerX / 2;
                    posY = 0;
                } else if ((-degrees) >= 180) {
                    posX = centerX;
                    posY = 0;
                } else if ((-degrees) >= 135) {
                    posX = centerX;
                    posY = 0;
                } else if ((-degrees) >= 85) {
                    posX = centerX;
                    posY = centerY;
                }
                
                if ((-degrees) >= 225) {
    
                    can.save();
                    Bitmap dst = bitmap
                            .createBitmap(bitmap, 0, 0, centerX, centerX);
                    paint.setAntiAlias(true);
                    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
                    Bitmap src = bmpBg.createBitmap(bmpBg, 0, 0, centerX, centerX);
                    can.drawBitmap(src, 0, 0, paint);
                    can.restore();
    
                    can.save();
                    dst = bitmap.createBitmap(bitmap, centerX, 0, centerX, height);
                    paint.setAntiAlias(true);
                    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
                    src = bmpBg.createBitmap(bmpBg, centerX, 0, centerX, height);
                    can.drawBitmap(src, centerX, 0, paint);
                    can.restore();
    
                } else {
                    can.save();
                    Bitmap dst = bitmap.createBitmap(bitmap, posX, posY, width
                            - posX, height - posY);
                    paint.setAntiAlias(true);
                    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
                    Bitmap src = bmpBg.createBitmap(bmpBg, posX, posY,
                            width - posX, height - posY);
                    can.drawBitmap(src, posX, posY, paint);
                    can.restore();
                }
            }
            //绘制遮罩层位图
            canvas.drawBitmap(bitmap, 0, 0, null);
            
            // 画中间进度百分比字符串
            paint.reset();
            paint.setStrokeWidth(0);
            paint.setColor(textColor);
            paint.setTextSize(textSize);
            paint.setTypeface(Typeface.DEFAULT_BOLD);
            int percent = (int) (((float) progress / (float) max) * 100);// 计算百分比
            float textWidth = paint.measureText(percent + "%");// 测量字体宽度,需要居中显示
    
            if (isDisplayText && percent != 0) {
                canvas.drawText(percent + "%", centerX - textWidth / 2, centerX
                        + textSize / 2 - 25, paint);
            }
            //画底部开口处标题文字
            paint.setTextSize(textSize/2);
            textWidth = paint.measureText(title);
            canvas.drawText(title, centerX-textWidth/2, height-textSize/2, paint);
        }

    3、设置比例进度的同步接口方法,主要供刷新进度比例用。

    /**
         * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
         * 刷新界面调用postInvalidate()能在非UI线程刷新
         * @author caizhiming
         */ 
        public synchronized void setProgress(int progress) {
            if(progress < 0){
                throw new IllegalArgumentException("progress must more than 0");
            }
            if(progress > max){
                this.progress = progress;
            }
            if(progress <= max){
                this.progress = progress;
                postInvalidate();
            }
        }

    五、源码下载

    真题园网http://www.zhentiyuan.com

    源码下载:http://www.demodashi.com/demo/14680.html
     

  • 相关阅读:
    意料之外,情理之中,Spring.NET 3.0 版本发布-
    学习究竟是为了什么?
    测量软件应用系统的聚合复杂度【翻译稿】
    关键字New,如阴魂不散
    选择IT事业,意味着终身学习
    华为机试001:字符串最后一个单词的长度(华为OJ001)
    C++版
    C++版
    C++版-剑指offer 面试题6:重建二叉树(Leetcode105. Construct Binary Tree from Preorder and Inorder Traversal) 解题报告
    C++版
  • 原文地址:https://www.cnblogs.com/JczmDeveloper/p/4836278.html
Copyright © 2020-2023  润新知