iOS中hitTest如何扩大一个视图的点击区域。

1.问题:之前在面试时被问到这样一个问题:如何扩大一个给定视图的点击区域,或者说如何让一个视图在当前视图外的子视图也能响应点击事件。

2.场景:可能大家不太理解这种问题是什么意思,现在给定场景。我们在开发中经常会遇到这样问题,上传图片的时候,我们选中图片后要删除选中的图片,会在右上角添加一个删除按钮。这时候删除按钮就会有一半,或者全部都出现在当前图片视图的bounds外,导致不好点或者不能点的情况出现,那就需要用到我们今天的命题,扩大视图的点击区域。

3.前提:在解决这个问题的时候,我们先要清楚两个东西

           1.触摸时间的touch的产生顺序。一个APP中touch时间是如何产生的,当我们手指接触到屏幕时,通过硬件产生一个touch

      然后以 touch -> UIApplication -> UIWindow -> UIViewController.View -> subviews -> ... ->最终找到最合适的响应者 or 丢弃

          2.响应链:当我们找到最合适的响应者的时候,我的view就开始进行touch时间的响应。顺序恰恰和产生相反。

             以 view -> supView ->... -> UIViewController -> UIWindow -> UIApplication  or(丢弃)。

4.方法:hitTest,这个方法就负责进行touch事件的传递,当事件通过触摸点传过来之后,由这个类的对象通过hitTest方法判断传递给哪些subView,或者丢弃。一个事件会丢弃有四种情况

           ①:view.userinterfaceEnable == NO

           ②:view.hidden == YES

           ③:view.alpha < 0.05

           ④:点击区域 超出 view.bounds 之外。

  所以我们不难推断hitTest的实现。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    
    if (self.hidden == NO || self.alpha < 0.05 || self.userInteractionEnabled == NO) {
        //1.当满足这几个条件时,直接丢弃touch事件,不再向下分发。
        return nil;
    }else{
        if (![self pointInside:point withEvent:event]) {
            //2.如果点击point在视图之外,丢弃
            return nil;
        }else{
            //3.分发给子视图
            if (self.subviews.count > 0) {
                for (UIView *subView in self.subviews) {
                    UIView *hitTestSubView = [subView hitTest:point withEvent:event];
                    return hitTestSubView;
                }
            }else{
                return self;
            }
        }
    }
}

5.解决,所以我们只需要在改变分发策略,让他在视图外同样分发给子视图就行了。

class HitTestView: UIView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if isHidden == true || alpha < 0.05 || isUserInteractionEnabled == false {
           return super.hitTest(point, with: event)
        }else{
            if self.point(inside: point, with: event) {
                return super.hitTest(point, with: event)
            }else{
                //1.有subView时交给subView 去响应
                for subview in self.subviews{
                    let coverPoint = self.convert(point, to: subview)
                    return subview.hitTest(coverPoint, with: event)
                }
                
                //2.没有subView时交给自己来响应,也就是说你无论在哪儿点击都会响应(扩大点击区域)
                //当然这里如果你想扩大到一定的返回,可以在此处加限制
                let isResponse:Bool = false
                if isResponse {
                    return self
                }else {
                    return nil
                }
                //3.如果你不想当没有subView时就随便响应,j就返回nil
                return nil
            }
        }
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print(#function)
    }

}

6.参考:iOS hitTest

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值