自定义View—使用clipPath或者BitmapShader实现圆角图片
2015-08-16 22:30
786 查看
实现圆角图片的方式有三种,上篇文章中是使用了Xfermode,这篇文章则将总结剩下的两种clipPath、BitmapShader。这里我们跟上一篇一样继承自ImageView。
Canvas类中提供对画布的裁剪的方法,有clipPath对具体路径进行裁剪,有clipRect对具体矩形进行裁剪,有clipRegion对具体区域进行裁剪。我们先看clipPath的两个方法:
clipPath(Path path)
Intersect the current clip with the specified path.
clipPath(Path path, Region.Op op)
Modify the current clip with the specified path.
我们注意到第二个方法里有个参数Region.Op op,这是一个枚举值:
我们把之前的区域设为A,裁剪的区域为B,则以上枚举值的意义如下:
Region.Op DIFFERENCE
显示A-B
Region.Op INTERSECT
显示 A与B的交集
Region.Op REPLACE
显示B
Region.Op REVERSE_DIFFERENCE
显示B-A
Region.Op UNION
显示A与B的并集
Region.Op XOR
显示 A与B的并集-A与B的交集
不带Op参数的clipPath(Path path)则默认为使用INTERSECT。
了解这些后,我们就可以使用clipPath、重写onDraw来实现圆角图片了。首先需要对canvas进行裁剪,如何裁剪呢?我们需要的是圆角的图片,因此需要将canvas裁剪成圆角矩形的canvas,使得draw出来的是圆角的矩形。
分析:代码中的canvas.clipPath(path, Region.Op.INTERSECT);
之前的区域是整个canvas,而裁剪后的区域的圆角矩形,我们的目的是圆角矩形,因此传入的Op参数可以REPLACE,也可以是INTERSECT,或者不传参数。
圆角图片有很多开源的代码,例如
https://github.com/vinc3m1/RoundedImageView
这个提到:
does not use a clipPath which is not hardware accelerated and not anti-aliased.
does not use setXfermode to clip the bitmap and draw twice to the canvas.
而查看其源代码,我们可以发现它是用BitmapShader实现的,因此我们可以说BitmapShader真是不负众望。
BitmapShader是Shader的一个子类,Shader,我们可以理解为着色器,也就是说在设置完画笔的属性之后,再去绘制形状,会以找个着色器来着色。BitmapShader则允许这个着色器为Bitmap。
Shader是Paint的一个属性,可以通过paint.setShader()来设置。
我们先看看BitmapShader对象是如何创建的:
第一个参数是Bitmap,说明着色器的Bitmap来源,后面的两个参数为TileMode,取值有三种:
CLAMP 拉伸
REPEAT 重复
MIRROR 镜像
也就说,如果图片的长宽不足,可以选择以重复、拉伸、镜像的方式来填充。
接下来的事情就简单了,再设置完paint的bitmapshader,只需要绘制一个圆角矩形就好,paint就会以bitmap的方式来对这个矩形进行着色。
公共部分
无论是使用哪种方法,都需要自定义的属性和在构造器中获得相应的属性,因此将这部分放到一起。自定义属性
我们这个圆角图片可以定义图片的圆角度数,因此需要自定义这个属性如些:[code]<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RoundImageView"> <attr name="radius" format="dimension" /> </declare-styleable> </resources>
在构造器中获得自定义属性
[code]private static final String TAG = "RoundImageView"; private Paint mPaint; private Xfermode xfermode; /** 图片缩放的比例 */ private float scale = 1.0f; /** 圆角半径 */ private float mRadius; /** 默认的圆角半径 */ private static final int DEFAULT_RADIUS = 10; public RoundImageView(Context context) { this(context, null); } public RoundImageView(Context context, AttributeSet attr) { super(context, attr); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); TypedArray ta = context.getTheme().obtainStyledAttributes(attr, R.styleable.RoundImageView, 0, 0); mRadius = ta.getDimensionPixelSize(R.styleable.RoundImageView_radius, (int) TypedValue .applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_RADIUS, getResources() .getDisplayMetrics())); Log.e(TAG, "mRadius:" + mRadius); ta.recycle(); }
获得Bitmap
我们绘制时,需要用到Bitmap,因此需要获得资源src对应的Bitmap。[code]/** * 获得Bitmap */ private Bitmap getBitmap() { Bitmap bm = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Config.ARGB_8888); Drawable drawable = getDrawable(); Canvas drawableCanvas = new Canvas(bm); // 计算缩放 int drawablewidth = drawable.getIntrinsicWidth(); int drawableheight = drawable.getIntrinsicHeight(); int width = getMeasuredWidth(); int height = getMeasuredHeight(); scale = Math.min(width * 1.0f / drawablewidth, height * 1.0f / drawableheight); Log.e(TAG, scale + ""); // 缩放 drawable.setBounds(0, 0, (int) (drawablewidth * scale), (int) (drawableheight * scale)); drawable.draw(drawableCanvas); return bm; }
clipPath实现圆角图片
首先需要说的一点是clipPath在api18之前都不支持硬件加速,因此在构造器中需要关闭硬件加速,如下[code]setLayerType(LAYER_TYPE_SOFTWARE, mPaint);
Canvas类中提供对画布的裁剪的方法,有clipPath对具体路径进行裁剪,有clipRect对具体矩形进行裁剪,有clipRegion对具体区域进行裁剪。我们先看clipPath的两个方法:
clipPath(Path path)
Intersect the current clip with the specified path.
clipPath(Path path, Region.Op op)
Modify the current clip with the specified path.
我们注意到第二个方法里有个参数Region.Op op,这是一个枚举值:
[code]public enum Op { DIFFERENCE(0), INTERSECT(1), UNION(2), XOR(3), REVERSE_DIFFERENCE(4), REPLACE(5); }
我们把之前的区域设为A,裁剪的区域为B,则以上枚举值的意义如下:
Region.Op DIFFERENCE
显示A-B
Region.Op INTERSECT
显示 A与B的交集
Region.Op REPLACE
显示B
Region.Op REVERSE_DIFFERENCE
显示B-A
Region.Op UNION
显示A与B的并集
Region.Op XOR
显示 A与B的并集-A与B的交集
不带Op参数的clipPath(Path path)则默认为使用INTERSECT。
了解这些后,我们就可以使用clipPath、重写onDraw来实现圆角图片了。首先需要对canvas进行裁剪,如何裁剪呢?我们需要的是圆角的图片,因此需要将canvas裁剪成圆角矩形的canvas,使得draw出来的是圆角的矩形。
[code]@Override protected void onDraw(Canvas canvas) { canvas.save(); Path path = new Path(); path.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()), mRadius, mRadius, Path.Direction.CW); // 先对canvas进行裁剪 canvas.clipPath(path, Region.Op.INTERSECT); Bitmap bm = getBitmap(); // 绘制bitmap canvas.drawBitmap(bm, 0, 0, mPaint); canvas.restore(); }
分析:代码中的canvas.clipPath(path, Region.Op.INTERSECT);
之前的区域是整个canvas,而裁剪后的区域的圆角矩形,我们的目的是圆角矩形,因此传入的Op参数可以REPLACE,也可以是INTERSECT,或者不传参数。
使用BitmapShader实现圆角图片
我们这时可能会发现之前的两种方法都有其缺点,Xfermode需要我们绘制两次,而clipPath不支持硬件加速,因此我们将希望寄予BitmapShader。圆角图片有很多开源的代码,例如
https://github.com/vinc3m1/RoundedImageView
这个提到:
does not use a clipPath which is not hardware accelerated and not anti-aliased.
does not use setXfermode to clip the bitmap and draw twice to the canvas.
而查看其源代码,我们可以发现它是用BitmapShader实现的,因此我们可以说BitmapShader真是不负众望。
BitmapShader是Shader的一个子类,Shader,我们可以理解为着色器,也就是说在设置完画笔的属性之后,再去绘制形状,会以找个着色器来着色。BitmapShader则允许这个着色器为Bitmap。
Shader是Paint的一个属性,可以通过paint.setShader()来设置。
我们先看看BitmapShader对象是如何创建的:
[code]bitmapShader = new BitmapShader(bm, TileMode.CLAMP, TileMode.CLAMP);
第一个参数是Bitmap,说明着色器的Bitmap来源,后面的两个参数为TileMode,取值有三种:
CLAMP 拉伸
REPEAT 重复
MIRROR 镜像
也就说,如果图片的长宽不足,可以选择以重复、拉伸、镜像的方式来填充。
接下来的事情就简单了,再设置完paint的bitmapshader,只需要绘制一个圆角矩形就好,paint就会以bitmap的方式来对这个矩形进行着色。
[code] @Override protected void onDraw(Canvas canvas) { Bitmap bm = getBitmap(); bitmapShader = new BitmapShader(bm, TileMode.CLAMP, TileMode.CLAMP); mPaint.setShader(bitmapShader); canvas.drawRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()), mRadius, mRadius, mPaint); }
相关文章推荐
- 冈萨雷斯数字图像处理中科院&电子科大halcon/C++/Opencv视频教程下载
- android源码的编译问题总结
- Java源码分析系列
- 修改数据
- django_学习笔记0816
- 九宫格求解,结果为何不能输出?
- 西普部分CTF题目(web)(持续更新)
- hdu 1131 Count the Trees (卡特兰数的应用)
- Android中的多线程之handler
- tomcat环境搭建问题汇总
- The Tree ||
- CSS样式 初学
- 如何在自己的Windows系统上 架设服务器并开发网站,然后连入外网供外界访问?(JDK+Tomcat+花生壳)
- Word Break
- Microsoft Dynamics CRM 2015 数据管理 功能 介绍
- Microsoft Dynamics CRM 2015 数据管理 功能 介绍
- 函数指针C++和回调函数
- 在VMware做虚拟映射进行网络连接的步骤
- 梦想永远那么近——《白箱》后日谈
- 机房重构VB.Net版进行中