自定义View—使用Xfermode实现圆角图片
来源:互联网 发布:螺纹钢月线数据 编辑:程序博客网 时间:2024/06/14 18:19
有些时候,棱角分明的矩形可能不满足我们的需求。我们希望图片是圆角,显得图片更加圆滑,例如手q的头像是圆形的。虽说我到现在没做过一个像样的项目,但是还是先学习下,厉兵秣马。
这篇博客主要学习自hongyang前辈的教程,同时也增加自己,作为一个新手,的学习过程,使之详细。此次的圆角图片继承自ImageView,这样可以节省onMeasure步骤。
Xfermode和他的儿子们
实现圆角图片,我们需要用到Xfermode这个类。Xfermode有三个子类:
AvoidXfermode , PixelXorXfermode , PorterDuffXfermode
然而,前两个子类已是弃子,在Android官方文档中描述为“Deprecated since API level 16”,因此就不做介绍。
PorterDuffXfermode是画布绘制的合成模式,也就是两张图的相交之后的显示方式。正常绘制时,新的不透明的会覆盖旧的图,而通过Paint.setXfermode()可以设置相交的显示方式。
使用PorterDuffXfermode,需要创建PorterDuffXfermode的对象,例如:
Xfermode xfermode = new PorterDuffXfermode( PorterDuff.Mode.Clear)
这里传进去的PorterDuff.Mode在官方文档上介绍说有18种,常用的为下面的16种:
引用:
- PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。- PorterDuff.Mode.SRC
显示上层绘制图片- PorterDuff.Mode.DST
显示下层绘制图片- PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。- PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。- PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。- PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。- PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。- PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。- PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分- PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分- PorterDuff.Mode.XOR
异或:去除两图层交集部分- PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深- PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色- PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色- PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色
下面为图说明,先画DST图,设置不同的Mode,再画SRC图:
值得说明的是,我并没有对所有的模式进行测试,而是对DST_IN和SRC_IN进行了测试,其他的我相信都大同小异,测试代码如下:
int sc = canvas.saveLayer(0, 0, width, height, mPaint, Canvas.ALL_SAVE_FLAG);// 先画DSTcanvas.drawBitmap(bm, 0, 0, mPaint);// 设置XfermodemPaint.setXfermode(xfermode);// 再画SRCcanvas.drawBitmap(bm, 0, 0, mPaint);// 设置Xfermode为空mPaint.setXfermode(null);canvas.restoreToCount(sc);
圆角图片步骤
自定义属性
我们这个圆角图片可以定义图片的圆角度数,因此需要自定义这个属性如些:
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="RoundImageView"> <attr name="radius" format="dimension" /> </declare-styleable></resources>
在构造器中获得自定义属性
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); xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); 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(); }
重写onDraw方法
① 绘制图片我们需要通过canvas.drawBitmap(Bitmap bm)方法,因此,我们第一步需要获得资源图片的Bitmap对象。而父类ImageView只提供getDrawable()方法来获得Drawable对象,因此需要把Drawable转为Bitmap。
② 另一方面,如果图片资源比较小,而我们设置的width和height过大,我们需要根据比例进行缩放。
考虑以上两点后,onDraw的代码就大致确定了:
@Override protected void onDraw(Canvas canvas) { 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); // 绘制圆角矩形 // 下面的方法api已经变为21了,所以不能使用 // canvas.drawRoundRect(0, 0, width, height, mRadius, mRadius, mPaint); int sc = canvas.saveLayer(0, 0, width, height, mPaint, Canvas.ALL_SAVE_FLAG); // 绘制资源图片 canvas.drawBitmap(bm, 0, 0, mPaint); mPaint.setXfermode(xfermode); // 绘制形状产生的图片 canvas.drawBitmap(makeSrc(width, height), 0, 0, mPaint); mPaint.setXfermode(null); canvas.restoreToCount(sc); } private Bitmap makeSrc(int width, int height) { Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(Color.BLACK); c.drawRoundRect(new RectF(0, 0, width, height), mRadius, mRadius, p); return bm; }
以上代码注意点:
- canvas.drawRoundRect(0, 0, width, height, mRadius, mRadius, mPaint); 只有api21和以上才能使用,因此需要用drawRoundRect(new RectF(0, 0, width, height), mRadius, mRadius, p);来代替。
- saveLayer和restoreToCount 不要忘记了,否则可能会失败,至少我真机测试时会失败。
- 绘制形状时,不直接使用drawRoundRect方法,而是像makeSrc方法里那样产生一张绘制有形状的Bitmap,否则也可能会失败。
效果图
后记
如有问题,可以在评论中追问。
- android官方文档:http://www.androidcommunitydocs.com/reference/android/graphics/Xfermode.html
- android官方例子 sdk-samples-android17-ApiDemo-graphics-Xfermode类
- 鸿洋前辈的教程:http://blog.csdn.net/lmj623565791/article/details/42094215
- 源码地址:http://download.csdn.net/detail/u012933743/8803383
- github上使用Xfermode绘制各种形状的开源项目:https://github.com/MostafaGazar/CustomShapeImageView
- 自定义View—使用Xfermode实现圆角图片
- Xfermode实战 实现圆形、圆角图片
- Android 完美实现图片圆角和圆形(Xfermode,重写View)
- Android使用Xfermode图形渲染方法实现自定义圆形、圆角和椭圆ImageView
- Xfermode实现圆角矩形或者圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片
- 利用Xfermode模式实现图片的圆角效果
- Android Xfermode 实战 实现圆形、圆角图片
- Android Xfermode 实战 实现圆形、圆角图片(1)
- Android Xfermode 实战 实现圆形、圆角图片
- MyBatis学习总结(七)——Mybatis缓存
- GCD&&LCM的一些经典问题
- 关于支付宝由关联项目,到打包到自己项目。
- 关于listview的适配器Adapter里面的数据集合Arraylist list指针问题。
- android仿QQ消息列表拖拽气泡效果源码读后感(1)
- 自定义View—使用Xfermode实现圆角图片
- 自定义Notification。多文字,或者图片等等。
- 经典算法之二分搜索技术
- 获取WebView加载网页后的cookies
- MyBatis学习总结(八)——Mybatis3.x与Spring4.x整合
- TextView文字阴影效果。
- python处理blog文件数据
- 约么,关于果壳活性炭的各种注意事项正在集结中
- jdbc连接数据库