登录

去注册

登录

注册

去登录

注册

每日一问 Android 常见的制作圆角方案,有哪几种常见方式? 在Android P上什么兼容性问题

xiaoyang   2019-07-21   收藏

据说最新有的方案在P上有兼容性问题。

6

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 上的兼容问题,暂时还没有发现。

回复
4

我们平时在开发中,用到圆角的场景,除按钮之外最多的应该就是用户头像了吧,
按钮的话,一般都是固定的素材,这种可以用Shape来实现。
但头像是一张图片,而且可以更换,用Shape肯定不行了。


那么有哪些方法呢?

爱折腾的同学会比较喜欢自己动手,用的最多的应该就是PorterDuffXfermode了,
它一共有18种模式(注意是模式不是效果,不同的模式通过不同的写法最终出来的效果也可能是一样),可以实现圆角效果的Mode,通常有这三种:

  1. SRC_IN
  2. SRC_ATOP
  3. MULTIPLY

但我们一般用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] 是怎么样的呢?

其实也就是进行圆角处理之前的那个矩形了(原始尺寸)。

回复
2

1. 使用xml
2. 使用GradientDrawable

public static GradientDrawable getDrawable(int radius, int fillColor, int width, int strokeColor) {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setCornerRadius(radius);
gradientDrawable.setColor(fillColor);
gradientDrawable.setStroke(width, strokeColor);
return gradientDrawable;
}

3. 自定义Drawable,如ShadowDrawable
以上三种方法设置通常用于圆角背景,如TextView,Button等,无法进行裁剪,不适用于ImageView

4. 使用canvas clipPath进行裁剪(有锯齿,不考虑)
5. 使用xformode进行裁剪(需要关闭硬件加速)
6. 使用ViewOutlineProvider裁剪(Android5.0以上)
7. 参照Glide办法,使用BitmapShader,将原始的内容画到一个临时的bitmap上,使用BitmapShaper将它设置成画笔,
然后通过canvas画一个圆角区域,如:

BitmapShader shader = new BitmapShader(oldBitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(shader);
canvas.drawPath(radiusPath, mPaint);

回复
1

每周3/3

回复

删除留言

确认删除留言,会导致相关评论丢失?

取消 确定