技术:Android+java
 

概述

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

详细

一、概述

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

大师的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();
}
}

四、项目代码目录结构图

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

Android 自定义控件-高仿猎豹清理大师自定义内存开口圆环控件的更多相关文章

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

    一.概述 看见猎豹清理大师的内存开口圆环比例进度 挺有意思的,于是就是想自己实现下这样的效果,于是反编译了猎豹清理 大师的app看了下,原来是有两张图,于是脑子里就过了下思路,利用上下两张图,旋转上面 ...

  2. android版高仿淘宝客户端源码V2.3

    android版高仿淘宝客户端源码V2.3,这个版本我已经更新到2.3了,源码也上传到源码天堂那里了,大家可以看一下吧,该应用实现了我们常用的购物功能了,也就是在手机上进行网购的流程的,如查看产品(浏 ...

  3. android - 自定义(组合)控件 + 自定义控件外观

    转载:http://www.cnblogs.com/bill-joy/archive/2012/04/26/2471831.html android - 自定义(组合)控件 + 自定义控件外观   A ...

  4. Android创建自定义的布局和控件

    Android的自带布局有framelayout.linerlayout.relativelayout,外加两个百分比布局,但是这些无法灵活的满足我们的需要,所以我们要自己自定义并引入自己的布局.首先 ...

  5. 使用VideoView自定义一个播放器控件

    介绍 最近要使用播放器做一个简单的视频播放功能,开始学习VideoView,在横竖屏切换的时候碰到了点麻烦,不过在查阅资料后总算是解决了.在写VideoView播放视频时候定义控制的代码全写在Actv ...

  6. 获取 AlertDialog自定义的布局 的控件

    AlertDialog自定义的布局 效果图: 创建dialog方法的代码如下: 1 LayoutInflater inflater = getLayoutInflater(); 2 View layo ...

  7. WPF自定义LED风格数字显示控件

    原文:WPF自定义LED风格数字显示控件 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199988899/article/de ...

  8. 动画--android图片点击放大动画,并遮挡旁边的控件

    http://blog.csdn.net/s13488941815/article/details/40649823: 首先是点击放大可以使用android自带的缩放动画,因为要遮盖其他控件,就需要控 ...

  9. asp.net读取用户控件,自定义加载用户控件

    1.自定义加载用户控件 ceshi.aspx页面 <html> <body> <div id="divControls" runat="se ...

随机推荐

  1. Guava之FluentIterable使用示例

    FluentIterable 是guava集合类中常用的一个类,主要用于过滤.转换集合中的数据:FluentIterable是一个抽象类,实现了Iterable接口,大多数方法都返回FluentIte ...

  2. Log Shipping搭建

    1.    概述 SQL Server 使用日志传送,您可以自动将“主服务器”实例上“主数据库”内的事务日志备份发送到单独“辅助服务器”实例上的一个或多个“辅助数据库”.事务日志备份分别应用于每个辅助 ...

  3. linux和windows时间同步问题(UTC&localtime)

    Linux使用 UTC,但是windows默认使用localtime.解决的办法如下(重启后生效). 进入windows使用regedit写入DWORD值(设置成十六进制"1"): ...

  4. [leetcode]Simplify Path @ Python

    原题地址:https://oj.leetcode.com/problems/simplify-path/ 题意: Given an absolute path for a file (Unix-sty ...

  5. RxJava【变换】操作符 map flatMap concatMap buffer MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. JavaScript类的写法

    js类的基本含义 我们知道,在js中,是没有类的概念的.类的所有实例对象都从同一个原型对象上继承属性,因此,原型对象是类的核心. 类是对象的抽象,而对象是类的具体实例.类是抽象的,不占用内存,而对象是 ...

  7. logistic回归(一)

    http://www.2cto.com/kf/201307/226576.html , 这个是Sigmoid函数,在这个回归过程中非常重要的函数,主要的算法思想和这个密切相关.这个函数的性质大家可以自 ...

  8. 【转载】.NET/C#-uploadify视频文件or大文件上传

    引言 之前使用Uploadify做了一个上传图片并预览的功能,今天在项目中,要使用该插件上传大文件.之前弄过上传图片的demo,就使用该demo进行测试.可以查看我的这篇文章: [Asp.net]Up ...

  9. ssh tunnel

    https://peppoj.net/2012/10/tunnel-http-traffic-encrypted-using-polipo-and-ssh/ --------------------- ...

  10. MFC中的KillTimer

    在Dialog中添加一个Timer. 用如下的代码停用一个Timer总是不好用: void CDialog2::OnTimer (UINT TimerVal) { ////////////////// ...