自定义view实现圆角图片
前两天想实现一个圆角图片的效果,通过网络搜索后找到一些答案。这里自己再记录一下,加深一下自己的认识和知识理解。
实现圆角图片的思路是自定义一个ImageView,然后通过Ondraw()重绘的功能,将drawable和一个圆形进行重叠绘制,这样就可以达到圆角的效果了。
下面开始具体实现圆角图片的过程。
第一步:写自定义属性文件
首先我们需要定义一个属性。在values目录下面新建一个xml文件,这个文件用来自定义一些属性,这样我们就可以写出自己的控件了。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RoundImageAttrs">
<attr name="BorderRadius" format="dimension"/>
<attr name="RoundType">
<enum name="circle" value="0"/>
<enum name="round" value="1"/>
</attr>
</declare-styleable>
</resources>
我来简单解释一下,declare-styleable这个标签就是用来自定义属性的,attr标签用来定义具体的属性,format可以指定很多种格式,具体有哪些属性,这里不做过多介绍了,请看博客中的介绍http://blog.csdn.net/mayingcai1987/article/details/6216655。在本例子中dimension表示尺寸的意思,这个应该在平常的开发中也用到。
同时还有一个enum的枚举类型,我们之前在用系统控件的时候,比如 android:orientation="vertical"就是比较典型的枚举类型,只不过在本例中我们自己实现了这个枚举类型。
定义好这个之后,我们就可以开始写我们的自定义view的代码了。最后注意的一点,这里的这个xml的名字可以随便命名(不过最好命名的比较有意义),android系统会自动找到的。
第二步,自定义View
这一步是本文中最重要的一步,也是实现自定义view的核心。那么我们从目的出发来探讨实现圆角image的方式。那么我们的目的是将图片变圆,在这里一般人可能有想到两种方式将图片变圆 1.把本来图片修改为圆形,其他地方都是透明2.只是让显示的时候,动态的裁剪到一些部分,然后让图片变圆。
这两种方法的优劣我想大家一眼就能看明白。直接修改图片,带来的后果是,我如果换了一种方式了,不再是圆角,而是星型,那么我们的图片已经毁掉了,没办法在重用了。而第二种方式就可以,无论我们换什么样的表现方式,我们是需要换一种裁剪的算法,就可以实现不同的形状的图片了,那么很显然,第二种方法是以不变应万变的。
那么现在,我们选定了第二种方式,那怎么实现呢?有人说我们自己写一个类,直接继承自view,然后所有的绘图和大小的计算我们都自己来搞,这样行吗?当然可行,但是我们可能是在重复造轮子,因为我们已经有了一个ImageView,而且它里面给我们做了很多关于图片的操作,我们何不继承自ImageView,然后做少量的工作,就可以实现圆角效果呢。方案确定,好,那我们就开始实现自己的类。
public class RoundImageView extends ImageView {
我们定义一个RoundImageView 继承自ImageView
private int mBorderRadius;
private int mType;
然后两个成员变量,分别对应于自定义属性文件中的BorderRadius和RoundType。
接下来我们重写构造函数
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RoundImageAttrs); mBorderRadius = a.getDimensionPixelSize(R.styleable.RoundImageAttrs_BorderRadius,
(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
mType = a.getInt(R.styleable.RoundImageAttrs_RoundType,0);
a.recycle();
Log.i("Log","mBorderRadius:"+mBorderRadius+"type:"+mType); }
首先是mPaint的初始化,这是一个画刷,用来画图形的,后面会说。
接下来是最为关键的代码, context.obtainStyledAttributes(attrs,R.styleable.RoundImageAttrs),这句代码用来获取控件上的自定义属性。
然后下面两句
mBorderRadius = a.getDimensionPixelSize(R.styleable.RoundImageAttrs_BorderRadius,
(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
mType = a.getInt(R.styleable.RoundImageAttrs_RoundType,0);
分别获取这两个属性的值,第一个比较复杂,涉及到默认值单位的转换,(这里10的代表默认值)
第二个就是获取RoundImageAttrs_RoundType,获取完毕后,记得一定要调用a.recycle();对资源进行释放。以便后面的其他代码可以访问这些属性资源。(理解的不透彻,但记住释放就ok)
到现在为止我们完成了万里长征第一步,获取到了我们自定义控件的属性了。
接下来就是我们的重头戏,重绘图片。下面我们重写了OnDraw函数
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
Bitmap bitmap = mWeakBitmap == null?null:mWeakBitmap.get();
if(bitmap == null || bitmap.isRecycled())
{
Drawable drable = getDrawable();
int width = drable.getIntrinsicWidth();
int height = drable.getIntrinsicHeight();
if(drable!=null)
{
bitmap = Bitmap.createBitmap(getWidth(),getHeight(),Config.ARGB_8888);
Canvas dcanvas = new Canvas(bitmap);
drable.draw(dcanvas);
if(mMashBitmap == null || mMashBitmap.isRecycled())
{
mMashBitmap = getShapeBitmap();
}
mPaint.reset();
mPaint.setFilterBitmap(false);
mPaint.setXfermode(mXfermode);
dcanvas.drawBitmap(mMashBitmap, 0,0, mPaint);
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0,0, null);
mWeakBitmap = new WeakReference<Bitmap>(bitmap); }
}
else
{
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0,0, null);
return;
}
}
上面的代码可能第一次看比较迷惑,各种paint还有canvas,drawable,各种区分不清。下面我结合代码都说说。
Bitmap bitmap = mWeakBitmap == null?null:mWeakBitmap.get();这句话是从一个弱引用中取得Bitmap图像,我们在成功创建圆形图像后,会保存起来,以供后面刷新使用。
接下来我们判断bitmap,如果为空说明还没有创建过。接下来我们通过getDrawable();获取当前ImageView的drawable,里面包含了原本的图像。
下面我们创建了一个临时的Bitmap对象,这个对象将保存经过我们处理之后的图像
bitmap = Bitmap.createBitmap(getWidth(),getHeight(),Config.ARGB_8888);
然后我们创建一个Canvas dcanvas = new Canvas(bitmap); drable.draw(dcanvas); 通过drawable的draw方法将原来ImageView的图像绘制到dcanvas上(其实也是画到bitmap上)。 接下来我们获取图形(这里是圆形,后面大家可以自己定义形状)mMashBitmap = getShapeBitmap();(这个函数我们后面介绍),然后我们设置了paint的属性
private Xfermode mXfermode = new PorterDuffXfermode(Mode.DST_IN);
mPaint.setXfermode(mXfermode);
这个mXfermode代表的意思是,当用paint画图时,新绘制的图像与原图像的关系。给大家一张图,就很容易理解各种绘制方式了。
,在本例子中用的就是DST_IN,想必这张图一看就明白。paint配置完后,我们就开始将新的形状绘制到原来的图像上
dcanvas.drawBitmap(mMashBitmap, 0,0, mPaint); 此时,bitmap中保存的就是叠加之后的图片了,也就是我们最终需要的圆角图片了。最后我们将这个bitmap绘制到OnDraw函数给我们传递进来的
canvas上,所有工作就基本做完了。canvas.drawBitmap(bitmap, 0,0, null);
最后将绘制好的图片保存起来。mWeakBitmap = new WeakReference<Bitmap>(bitmap); 下一次执行ondraw 的时候,我们就直接用保存好的bitmap进行绘制了,也就是我们代码中else的部分。 最艰难的部分说完了,哈哈,如果不理解还是得多看几遍。接下来的工作就轻松了很多,对了,我们还没有实现之前那个绘制形状的函数呢。我们来绘制把。很容易的。
private Bitmap getShapeBitmap()
{
Bitmap bit = Bitmap.createBitmap(getWidth(),getHeight(),Config.ARGB_8888);
Canvas can = new Canvas(bit);
Paint pa = new Paint(Paint.ANTI_ALIAS_FLAG);
pa.setColor(Color.BLACK); if(mType == 0)
{
can.drawCircle(getWidth()/2, getHeight()/2, mBorderRadius, pa);
}
return bit; }
看看上面的代码,是不是很熟悉,我们之前已经接触过基本的画图方法了。想必,不用解释了,一眼都能看明白。这里我只实现了画圆的,大家可以各自发挥想想,画出各种各样的形状,哈哈,是不是很容易,我们自己实现了圆角图像,同时对于android自定义view的绘制也有了大致了解。
对了,这里面还有一个问题,如果用户想动态修改图片怎么办,我们在内存里面保存了一个旧的图片,该怎么更新呢。其实好办,我们只需要做下面的操作就行
public void invalidate()
{
mWeakBitmap = null;
if (mMashBitmap != null)
{
mMashBitmap.recycle();
mMashBitmap = null;
}
super.invalidate();
}
这个函数是当view视图重绘的时候执行的,于是乎,当我们更换图片后,让view重绘,就可以将之前保留的旧的图片信息清空啦。
真不容易啊,终于写完了,竟然写了三个小时,看来以后自己还是得多多些博客了,不过通过写文章, 更加加深了认识,值得。
最后如果转载,别忘了注明源地址噢,谢谢各位看官。
转载请注明出处http://www.cnblogs.com/gaoteng/p/4222207.html www.gaotenglife.com
自定义view实现圆角图片的更多相关文章
- 自定义View之一圆形图片
自定义View的方法 对现有控件进行扩展 通过组合来实现新的控件 重写View来实现全新的控件 本篇文章主要讲对现有控件的扩展 1.圆形图片控件 自定义View,对ImageView的扩展 重写onD ...
- Android 自定义View消除锯齿实现图片旋转,添加边框及文字说明
先看看图片的效果,左边是原图,右边是旋转之后的图: 之所以把这个写出来是因为在一个项目中需要用到这样的效果,我试过用FrameLayout布局如上的画面,然后旋转FrameLayout,随之而来也 ...
- Android 自定义View修炼-Android实现圆形、圆角和椭圆自定义图片View(使用BitmapShader图形渲染方法)
一.概述 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的.实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader.本文直接继 ...
- Android 自定义View修炼-实现自定义圆形、圆角和椭圆ImageView(使用Xfermode图形渲染方法)
一:简介: 在上一篇<Android实现圆形.圆角和椭圆自定义图片View(使用BitmapShader图形渲染方法)>博文中,采用BitmapShader方法实现自定义的圆形.圆角等自定 ...
- CALayer 知识:创建带阴影效果的圆角图片图层和创建自定义绘画内容图层
效果如下: KMLayerDelegate.h #import <UIKit/UIKit.h> @interface KMLayerDelegate : NSObject @end KML ...
- 自定义标签+阻尼动画+圆角图片+titleBar随滑动渐隐和显示
写这个小Demo,也是因为刚好手里没什么事然后看到很多朋友还在好奇这个阻尼界面效果,还有自定义标签,其实这个标签因为现在Google已经有推出更好使用的东西可以替代,那就是“FlexboxLayout ...
- 安卓自定义View实现图片上传进度显示(仿QQ)
首先看下我们想要实现的效果如下图(qq聊天中发送图片时的效果): 再看下图我们实现的效果: 实现原理很简单,首先我们上传图片时需要一个进度值progress,这个不管是自己写的上传的方法还是使用第三方 ...
- Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解
Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...
- Android圆形图片不求人,自定义View实现(BitmapShader使用)
在很多APP当中,圆形的图片是必不可少的元素,美观大方.本文将带领读者去实现一个圆形图片自定View,力求只用一个Java类来完成这件事情. 一.先上效果图 二.实现思路 在定义View 的onMea ...
随机推荐
- skype for business server2015部署向导启动服务失败
命令行执行start-cspool失败 解决: 1.cmd执行servers.msc打开服务列表,将所有skype服务启动,默认是延迟启动 2.用管理员权限打开cmd,而不是普通权限 重新执行启动服务 ...
- myeclipse 复制项目不包含svn或CVS目录
目前只记录到2个方法:(SVN和CVS都适用) 方法一:导出法 1.右击需要cp的目录,点击export,General/File System 2.next 3.确认你选择的目录,并勾选:Creat ...
- 【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.2.虚拟机类加载机制
1.概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验. 转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 2.类加载顺序 类从被加载到虚拟 ...
- 重大漏洞!PHP multipart/form-data头部解析远程拒绝服务漏洞
"有些人看不懂,简单比喻来说吧:目前刚出的任何安全防护都不会拦,网站类专属漏洞 畸形数据包,2KB随机数据包,2M网速打死各种网站,cdn通挂!"PHP multipart/for ...
- 笔记,记事软件(RedbookNote, lifeopraph)
许多人重视记日记是因为它是一种以天为基础保存个人或商务信息的良好方式:持续跟踪每天的生活和思想上的点点滴滴,组织和巩固记忆.思考.商业交易.电子邮件.账单.未来计划.联系人列表,甚至是秘密信息.Lin ...
- 巧用padding生成正方形DIV
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 剑指offer 14 调整数组顺序使奇数位于偶数前面
牛客网上的题目还有一个额外的要求,就是不改变数组原始的前后数据,这种可以用队列来存储,或者把前后比较变为相邻的元素比较. 这个题目,主要要考察扩展性,用func函数就实现了扩展性.只需要改func函数 ...
- git忽略文件留存
##ignore this file##/target/ .classpath.project.settings /.settings/ ##filter databfile.sln file##*. ...
- [LuoguP2900] [USACO08MAR]土地征用(Land Acquisition)
土地征用 (Link) 约翰准备扩大他的农场,眼前他正在考虑购买N块长方形的土地.如果约翰单买一块土 地,价格就是土地的面积.但他可以选择并购一组土地,并购的价格为这些土地中最大的长 乘以最大的宽.比 ...
- Linq不分组求多列的和
我们需要写Linq查询语句,使用let来创建一个新的变量 Let 关键字 “let”关键字在查询语法中很有用.它会投影一个新的范围变量,允许重新使用表达式并使查询更具可读性. 例如: 这里需要写,两遍 ...