iOS不规则控件的点击事件

我们有时候会碰到这样的需求,比如我们某个菜单是圆形的,或者某个菜单是环形的,由于一些情况普通用户很少能感知到,可能导致我们对非矩形控件的事件处理都按照矩形的区域来处理了,虽然这样的实现也没有问题,但是如果有一些极端的不规则控件出现的时候,可能矩形的处理区域就无法满足需求,我们就需要一种更加精确的处理方式,来决定我们的事件到底分发给哪个subview。

差不多2年前的时候,国内很多TabBar的设计中间都有一个凸起的部分,当时还是很流行,如下图所示

这种UI实现起来也比较简单,我们只需要一张背景图片加上几个按钮的图片就可以了,至于中间的凸起部分,我们一般有两种处理方式:

1、设置TabBar的frame为图二所示的区域,然后中间的按钮的坐标设置成负数(iOS中,如果设置clipsToBounds=NO的情况,是可以显示出超过View区域的subview)。

2、设置TabBar的frame为图三所示的区域,然后剩下的正常设置

这两种方式都可以实现这种设计,但是都存在问题。图二中,由于中间的按钮有一部分不在TabBar的区域内,不再TabBar的区域不能响应事件,所以绿色阴影部分点击了之后无法达到预期的效果;图三中,TabBar透明区域遮住了后面的TableView的一部分,所以在图三绿色阴影区域内,无法响应TableView的滚动事件。相比之下,图三的处理方式对用户的操作影响会少一些,所以大部分都选择了图三所示的方式,当然这也看情况而视,主要是根据你凸起的大小来决定。

我们有没有一种方法来解决这种问题呢?即我们既希望用户点击凸起的地方能够响应TabBar事件,又希望在图三绿色阴影内能让TableView进行滚动。

答案显然是有的。

之前写过几篇文章,介绍iOS的事件分发(hitTest),我们在这里就需要用到这些知识了。我们需要在确定hitTestView的时候告诉UIKit,如果触摸区域在这些地方,就把事件分发给TabBar,在那些地方,你就不要分发给TabBar,你直接忽略TabBar,当作TabBar不存在就行了。

我们来实现一下如上所示的需求,我们首先选择图三所示的方法自定义TabBar。也就是定义TabBar的frame比较大,然后往里面添加组件,添加组件的代码比较零碎,就不在这里粘贴了。

补充一点知识,我们如何确定点击区域在如下图所示的区域内呢? 

这就是一点简单的数学知识。以TabBar左上角作为原点iOS视图坐标系中,假设凸起部分半径为40,超出的高度是20,圆心坐标为P(160, 40),则y>20的区域必须是TabBar的区域,而且距离中间凸起圆形区域的半径<40的区域也是TabBar的点击区域。也就是最终的这个不规则图形是由一个矩形和一个原叠和而成的。

根据我们的到的触摸点P1(x,y), 则如果 y > 20 || distance(P1,P) < 40,则返回响应的hitTestView为TabBar,否则,则返回nil(返回nil则认为当前TabBar不响应事件)。(两点间的距离的计算方式在这里就不说了)

上代码了

代码很简单的就实现了我们的需求,点击上图所示红色区域内的,TabBar去响应事件,反之,则交给TabBar下面的View去响应事件(hitTestBlock的这一部分可以直接参考之前提过的博客)。

关于TabBar的就说这么多,大家可以通过我的GitHub来下载Demo。Demo中的如果大家想更精确的测试,建议用模拟器+鼠标来操作。

我们根据如上的方法,就能得到一个解决方案。对于不规则的点击区域,我们只需要重写当前View的hitTest方法,然后根据一些数学公式来检测,如果满足条件,则返回当前View,否则,返回nil就可以了,当然前提是我们View的大小要覆盖我们期望的的点击区域,不能出现一些超出View区域的subview。

PS.有时候我们出现一些点击无法响应的情况,我们可以通过设置clipsToBounds=YES来验证是否是因为超出了父View的区域而导致的。

根据如上的思路,我来实现一个圆形的按钮,要求只有点击圆形内才响应事件,否则则不响应按钮事件

这个Demo的测试大家可以通过如上所示的git中下载,直接点击第二个标签测试就OK了~~

HitTestDemo地址

大家可以通过修改SKRoundButton,自行实现环形的按钮,无非就是数学公式而已,没有其他复杂的地方。

2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部