美文网首页iOS劝退指南
UIView 凸出部分可点击

UIView 凸出部分可点击

作者: tangbin583085 | 来源:发表于2017-09-09 17:18 被阅读11次

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

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

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

    相关文章

      网友评论

        本文标题:UIView 凸出部分可点击

        本文链接:https://www.haomeiwen.com/subject/hskejxtx.html