iOS劝退指南

UIView 凸出部分可点击

2017-09-09  本文已影响11人  tangbin583085

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

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;
}

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

上一篇下一篇

猜你喜欢

热点阅读