博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 自定义控件-高仿猎豹清理大师自定义内存开口圆环控件
阅读量:6257 次
发布时间:2019-06-22

本文共 7221 字,大约阅读时间需要 24 分钟。

技术:Android+java
 

概述

看见猎豹清理大师的内存开口圆环比例进度 挺有意思的,于是就是想自己实现下这样的效果,于是反编译了猎豹清理 大师的app看了下,原来是有两张图,于是脑子里就过了下思路,利用上下两张图,旋转上面张图以及使用 PorterDuffXfermode 来设置合适的渲染模式,就可以达到效果

详细

代码下载:

一、概述

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

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

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

二、演示效果图

11.gif

 

三、Xfermode渲染模式简介:

xfermode影响在Canvas已经有的图像上绘制新的颜色的方式 

* 正常的情况下,在图像上绘制新的形状,如果新的Paint不是透明的,那么会遮挡下面的颜色. 
* 如果新的Paint是透明的,那么会被染成下面的颜色 
下面的Xfermode子类可以改变这种行为: 
AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。 
PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素XOR操作。 
PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。

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

12.jpg

 

上面的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();        }    }

四、项目代码目录结构图

13.jpg

代码下载:

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

转载于:https://www.cnblogs.com/demodashi/p/10503286.html

你可能感兴趣的文章
adobe
查看>>
微信小程序中的分享事件
查看>>
HDU 6069 Counting Divisors【区间素筛】【经典题】【好题】
查看>>
使用HAXM为QEMU for Windows加速
查看>>
配置tomcat下war包可以自压缩
查看>>
idea中artifacts、facets、modules是什么意思?
查看>>
大数据下的Distinct Count(一):序
查看>>
android 打包
查看>>
FUCKED-BUG之临时对象的生死
查看>>
一句话开启XP_CMDSHELL
查看>>
【100题】第四十五题 雅虎面试两道题(矩阵判断、数组划分)
查看>>
MySQL基础知识
查看>>
HTML页面优化
查看>>
centos6下安装docker
查看>>
常见的算法PHP 版,自整理
查看>>
使用UITableView隐藏的复选功能
查看>>
自定义下拉菜单(按钮下面出现下拉菜单),失去焦点后,如何下拉菜单自动消失,以及弹出窗体位置一直变化问题...
查看>>
uboot指令和环境变量
查看>>
Python之模块(二)
查看>>
Python跳出循环语句continue与break的区别
查看>>