首页
学习
活动
专区
工具
TVP
发布

雕虫晓技(三)通用圆角布局全解析

1. 前言

之前,我在 GitHub 分享了一个开源库:https://github.com/GcsSloop/rclayout,这个库的主要目的是快速实现 Android中 的圆角需求,例如这样的效果。

分享这个库的时候只是觉得可能有用而已,但没有想到居然有了 800 多个 Star,看来有不少人像我一样,对圆角这一需求比较苦恼。

圆角算是一种比较常见的需求了,最常应用于图片,因此可以找到大量的自定义圆角 ImageView,不仅如此,一些比较流行的图片加载框架也都对圆角进行了支持,像 Fresco 和 Glide 很容易就能实现圆角效果。

除了图片之外,另一种比较常见的就是圆角背景了,例如 TextView 的背景或者 Button 的背景,针对于背景的圆角也很容易实现,一般用图片或者写一个 shape 就行了,例如:

上面的这些都是很容易实现的常见需求,但也有一种稍微特殊的常见需求,像下面这样:

由多个控件组合而成的条目,包括左上角一个角标、文字、文字背景和图片。

从上图可以看出啦,图片已经是圆角了,可是角标和文字背景依旧是方的,这显然不是我们想要的效果。

我之前对这种组合控件的处理方案是这样的:

角标:让设计重新切成带圆角的图,或者用支持圆角的ImageView进行展示。

文字背景:做一张带圆角的图,或者写一个底部是圆角的 shape。

这样展示是没有问题的,唯一比较麻烦的是改需求的时候,如果需要调整圆角的大小,需要分别调整三个地方:图片的圆角、角标的圆角、以及文字背景的圆角。如果一个地方忘记了调整,那么就会出现圆角无法对齐的情况。

正因如此,才想到开发一个圆角布局,将它们包裹起来,这样在不仅省去了处理角标和文字背景的麻烦,在修改需求的时候也只用修改一个地方就可以了。

2. 圆角布局原理

所谓圆角布局,本质上还是方形的,只不过是让圆角之外的部分不显示而已,简单来说就是对画布进行裁剪,也可以理解为设置一个遮罩,让目标区域外的内容不显示。

2.1 clipPath

在最初设计的时候,使用了 canvas 中 clipPath 的方法,该方法实现起来简单快速,原理如下:

2.1.1 构造一个带圆角的Path

初始化圆角信息和Path:

在 onSizeChanged 方法中根据 View 大小创建圆角 Path,在这里要注意对 padding 值的处理。

2.1.2 剪裁画布

直接使用 canvas 的 clipPath 方法进行剪裁。

这样一个圆角布局就实现了。

2.2 setXfermode

由于 clipPath 方法不支持抗锯齿,因此在一些分辨率较低的设备上边缘看起来非常粗糙,所以换了一种实现方案,利用画笔的模式来实现对内容区域的剪裁。

有关于画笔模式可以参考:http://www.gcssloop.com/customview/Color

2.2.1 Paint

创建画笔并设置其模式:

2.2.2 绘制

创建带有圆角 Path 的内容不变,只不过这次将绘制部分移动到了 dispatchDraw 里面,其实放在 drawChild 里面也是可以的,只要注意一下绘制顺序即可。

由于画笔模式是 SDT_IN,所以会显示原有内容区域和圆角Path区域交集的部分,并仅显示原有内容

2.3 支持圆形

知道了绘制原理想要支持圆形就很简单了,其实就是将带有圆角矩形的 Path 更换为带有圆形的 Path 即可。

为了支持圆形,我定义了一个 roundAsCircle 属性,只要检测到这个属性,就在 Path 中添加一个圆形,否则添加一个圆角矩形。

在支持圆形的时候有一个坑需要注意一下,就是控件长宽比不一致的情况下,由于是按照最短的边计算的,所以在长宽比不一致的情况下,直接向 Path 添加圆形, Path 是无法填充满画布的,在绘制的时候可能会出现圆形之外依旧有内容被绘制出来,所以这里使用了两个 moveTo 操作来让 Path 填充满画布(下文代码中注释部分)。

2.4 支持描边

支持描边就更简单了,就是基础的绘制操作,如下:

2.5 限定点击区域

上面虽然实现了的圆角、圆形的显示,但是没有被绘制出来的部分依旧是可以被点击的,因此需要限定点击区域,对超出显示区域的部分不进行响应。

这个原理也不复杂,主要是利用事件分发机制和 Region 的 contains 方法。

2.5.1 获取可点击区域

2.5.2 对超出区域外的事件不处理

使用 contains 方法判断事件的位置是否在区域内,如果不在区域内,就直接返回 false,表示不处理。

到此为止,有关通用圆角布局的核心内容就结束了。

3. 结语

通用圆角布局的原理并不复杂,而且代码实现起来也非常简单,感兴趣的可以在 Github 上看一下源码,核心代码不过 100 行左右。

RCLayout: https://github.com/GcsSloop/rclayout

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171229G0BHMX00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券