UIView 凸出部分可点击

在开发中,有些子控件超出了部分父控件的区域,导致子控件超出的区域处于不可点状态。

6FDA77D8-44CB-4AF4-BDB5-41BCF6FEAAA7.png

为解决这个问题,可以重写父类的2个方法中选其一

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;   // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;   // default returns YES if point is in bounds

1,产生的原因:

事件产生的时候,事件会顺着父控件——>子控件的方式传递,并且由最适合的UIResponse子控件来处理(UIView也是继承UIResponse),但是这个最适合的UIResponse如何找?就是通过上面的2个方法,一直遍历所有控件。而当点击凸出部分的时候,父控件执行了

- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; 

判断点击区域是否发生在自己身上,显然在默认的情况下判断为NO,所以就不会继续往子控件传该事件了,因此凸出的部分就不会接受到点击该事件。

2,解决方案1

了解了原因之后,我们可以重写父类方法(为什么不重写自己的- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; ?, 因为到父类就不往上传了,你还重写本身的方法干嘛呢~)

- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; 

让父类的可点击区域增加,增加的部分为凸出区域,代码如下:

/**
 重写点击区域

 @param point 点击点
 @param event 点击事件
 @return 返回布尔值
 */
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    
    // 默认为真直接返回
    BOOL inside = [super pointInside:point withEvent:event];
    if (inside) {
        return inside;
    }
    
    // 遍历所有子控件
    for (UIView *subView in self.subviews) {
        
        // 转换point坐标系
        CGPoint subViewPoint = [subView convertPoint:point fromView:self];
        // 如果点击区域落在子控件上
        if ([subView pointInside:subViewPoint withEvent:event]) {
            return YES;
        }
    }
    return NO;
}

3,解决方案2(别人写的,其实异曲同工)

后来发现别人也提供了一种思路(我还没发现和我的思路谁劣谁优,大神请指教)
既然是寻找最适合的UIResponse来处理,所以直接返回父类本身或者子控件就好了,重写父类的hitTest:(CGPoint)point withEvent:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // 先使用默认的方法来寻找 hit-TestView
    UIView *result = [super hitTest:point withEvent:event];
    // 如果 result 不为 nil,说明触摸事件发生在 tabbar 里面,直接返回就可以了
    if (result) {
        return result;
    }
    // 到这里说明触摸事件不发生在 tabBar 里面
    // 这里遍历那些超出的部分就可以了,不过这么写比较通用。
    for (UIView *subview in self.subviews) {
        // 把这个坐标从tabbar的坐标系转为subview的坐标系
        CGPoint subPoint = [subview convertPoint:point fromView:self];
        result = [subview hitTest:subPoint withEvent:event];
        // 如果事件发生在subView里就返回
        if (result) {
            return result;
        }
    }
    return nil;
}

至此,就可解决超出范围的点击事件了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 本文来自:http://ios.jobbole.com/84081/ 前言: 按照时间顺序,事件的生命周期是这样的...
    HackerOnce阅读 7,883评论 1 10
  • 在iOS开发中经常会涉及到触摸事件。本想自己总结一下,但是遇到了这篇文章,感觉总结的已经很到位,特此转载。作者:L...
    WQ_UESTC阅读 11,322评论 4 26
  • 好奇触摸事件是如何从屏幕转移到APP内的?困惑于Cell怎么突然不能点击了?纠结于如何实现这个奇葩响应需求?亦或是...
    Lotheve阅读 59,215评论 51 604
  • 7、不使用IB是,下面这样做有什么问题? 6、请说说Layer和View的关系,以及你是如何使用它们的。 1.首先...
    AlanGe阅读 4,472评论 0 1
  • 亲爱的自己,你好。 在浦东儿中心讲完故事后,在回家的路上。 有几个星期没讲故事了,依旧喜欢和小朋友互动的感觉,好亲...
    我是小小彦阅读 1,612评论 0 3

友情链接更多精彩内容