更多问答 >>
-
每日问答 Handler应该是大家再熟悉不过的类了,那么其中有个同步屏障机制,你了解多少呢?
2019-07-23 17:29 -
每日一问 听说过Handler中的IdleHandler吗?
2019-07-25 21:09 -
每日一问 很多时候我们说"Android16.6ms刷新一次屏幕" 正确吗?
2019-07-30 21:53 -
2019-08-01 21:44
-
每日一问 哪些 Context调用 startActivity 需要设置NEW_TASK,为什么?
2019-07-18 23:24 -
每日一问 如果项目要开始做编译速度优化,你会考虑从哪些地方入手?
2019-07-16 23:50 -
2019-07-14 21:09
-
每日一问 在Activity 的 onResume 方法中 view.postRunnable 能获取到 View 宽高吗?
2019-07-11 23:28 -
每日一问 在Activity 的 onResume 方法中 handler.postRunnable 能获取到 View 宽高吗?
2019-07-09 21:03
Android 开发中圆角基本上随处可见,一开始我们会想到直接用 CardView 或者是编写 Shape 文件来处理。对于小缘提到的用户头像,就想到了网上非常知名的https://github.com/hdodenhof/CircleImageView
但是,如果用 CardView,这无疑是增加布局层次,不好不好,Shape 文件?Shape 文件一般作为背景处理,抛开同样是增加布局层次以外,假设我们有成千上万个 Shape 文件,如何维护?不要觉得成千上万不可能,试想一下。这个白底4圆角一个 Shape,那个黄底4圆角一个 Shape,又来了一个白底10圆角,又是一个Shape文件。更容易出现的是,开发中很多童鞋一起维护,可能张三和李四写的都是白底10圆角,仅仅是名字不一样,又来了一个 Shape。oh,想想都很可怕对吧?
所以,换一种思路,直接在项目里面写一个自定义 View和自定义 ViewGroup来处理圆角或者是渐变或者是纯色背景,又或者是圆角边线的问题。我们可以在代码中通过自己自定义的属性来处理各种各样的 Shape 属性问题,比如 GradientDrawable 来处理 shapeMode。对于渐变色,GradientDrawable#Orientation 来处理渐变,我们甚至可以使用RippleDrawable来实现5.0系统以上的水波纹效果。
对于Android P 上的兼容问题,暂时还没有发现。
我们平时在开发中,用到圆角的场景,除按钮之外最多的应该就是用户头像了吧,
按钮的话,一般都是固定的素材,这种可以用Shape来实现。
但头像是一张图片,而且可以更换,用Shape肯定不行了。
那么有哪些方法呢?
爱折腾的同学会比较喜欢自己动手,用的最多的应该就是PorterDuffXfermode了,
它一共有18种模式(注意是模式不是效果,不同的模式通过不同的写法最终出来的效果也可能是一样),可以实现圆角效果的Mode,通常有这三种:
但我们一般用SRC_IN。
还有一种要自己动手实现的就是canvas的clipPath方法,
但因为裁剪后画布的四个角变成了圆弧(像素点是一粒粒很小的正方形,而不是圆形,为什么呢?因为如果是圆形的像素点的话,它们之间的缝隙会比正方形大很多(正方形不是没空隙?是啊那是理想状态,但是在屏幕上的像素点是有空隙的,只不过很小很小,你没察觉)),所以在一些屏幕分辨率比较低的手机上,锯齿效果就会比较明显(裁剪了一部分像素点,没有多余的像素去掩饰,但是你的内容实际大小却没有变化)。
产品经理轻轻地在你耳边说:这种方法好,就用这种方法,但是我不想看到锯齿,你想办法搞定它。
这怎么办呢?
用就用咯,但是他并没有说不可以再使用其他方法,那可以在clipPath的基础上再加个PorterDuffXfermode,就行了,嘿嘿。
那有没有不用自己动手搞的呢?
当然有,我们可以通过RoundedBitmapDrawableFactory的create方法创建一个RoundedBitmapDrawable来实现。
这个RoundedBitmapDrawable是一个抽象类,它在SDK有两个实现类,其中一个用来兼容5.0以下的系统。
好奇心比较重的同学可能会想:那它里面是怎么实现的呢?该不会也是PorterDuffXfermode吧?
不是的,它里面是使用BitmapShader来实现的。
其实BitmapShader的使用也是很简单的,创建实例后set进Paint里就行了。
听说有某种方式在9.0系统上有兼容性问题?
emmmm,这个我好像没有遇到过,不过我刚刚百度,不,谷歌了一下,发现在Github上的Issues:
https://github.com/SheHuan/NiceImageView/issues/6
上面的现象是圆角失效了(把整张图片draw了出来,超出了圆形框框范围)。
接着我看了一下这个库一开始的代码,发现它是用PorterDuffXfermode + SRC_IN实现的,也就是说,在9.0系统上,用这种方式是有问题的。
也看了修复Bug之后的代码:
加入了版本判断,9.0之前的系统继续使用原来的方法,9.0及以上的,Mode由SRC_IN改成了DST_OUT,并且,在draw圆角矩形(Path)之前,先用[另一个Path] - [当前要画的Path](也就是差集运算了,即得到的是后者没有的那部分),
这 [另一个Path] 是怎么样的呢?
其实也就是进行圆角处理之前的那个矩形了(原始尺寸)。
1. 使用xml
2. 使用GradientDrawable
3. 自定义Drawable,如ShadowDrawable
以上三种方法设置通常用于圆角背景,如TextView,Button等,无法进行裁剪,不适用于ImageView
4. 使用canvas clipPath进行裁剪(有锯齿,不考虑)
5. 使用xformode进行裁剪(需要关闭硬件加速)
6. 使用ViewOutlineProvider裁剪(Android5.0以上)
7. 参照Glide办法,使用BitmapShader,将原始的内容画到一个临时的bitmap上,使用BitmapShaper将它设置成画笔,
然后通过canvas画一个圆角区域,如:
方法汇总
1.shape.xml设置背景
2.cardview控件
3.自定Drawable,如系统提供的RoundedBitmapDrawable(为paint设置BitmapShader+drawRect)
4.使用Xfermode
5.使用clipPath(存在锯齿问题)
每周3/3