iOS按钮超出父控件部分任能响应点击事件和扩大/缩小响应范围

设计师在设计UI界面时,为了更加有个性通常会把界面设计的比较复杂实现。比如下面这个界面,中间凸起的那个发布按钮。
在这里插入图片描述

默认情况下,如果点击图片红色区域那块是没有任何响应的,系统会丢弃调这次触摸事件。那我们要怎么满足即使点击红色区域也响应发布按钮的点击事件呢?
首先我们必须了解事件的传递过程

  1. 当产生一触摸事件,这个触摸事件会被添加到UIApplication管理的事件队列中,所以首先接收到事件的是UIApplication。
  2. 由于队列的先进先出特性,UIApplication会取出最前面的事件传递给应用程序的主窗口也就是keyWindow。
  3. 让后在keyWindow里面找到最合适的响应者(view)来处理这个触摸事件

那么又是如何找到最合适的响应者(view)呢?

  1. 首先判断主窗口(keyWindow)自己是否能接受触摸事件
  2. 触摸点是否在自己身上
  3. 从后往前遍历子控件,重复前面的两个步骤
  4. 如果没有符合条件的子控件,那么就认为自己最合适处理

系统是通过下面两个核心的方法来查找的

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

所以我们就可通过重写以上的方法来达到我们的目的。我们通过一个例子来验证一下,如下图结构
在这里插入图片描述

橘色的按钮是添加在底部绿色的view里面,但是有一部分超出了绿色view的范围。默认情况下点击红色区域的按钮部分,这个橘色的按钮是不会有任何响应的。接下来我通过重写绿色view的- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event方法来让点击橘色按钮任何一个地方都能响应。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (self.userInteractionEnabled == NO || self.isHidden || self.alpha <= 0.01) {
        //这三种情况不能响应事件
        return nil;
    }
    //往前遍历子控件
    for (NSInteger i = self.subviews.count - 1; i >= 0; i--) {
        UIView *subView = self.subviews[i];
        //把点的坐标转换成子控件的坐标
        CGPoint newPoint = [self convertPoint:point toView:subView];
        if ([subView hitTest:newPoint withEvent:event]) {
            //找到最合适的view
            return subView;
        }
    }
    return [super hitTest:point withEvent:event];
}

然后通个控制台的打印信息,我们可以看到点击了橘色按钮任意一个地方都能响应点击事件,这样子就实现了按钮超出父控件部分任能响应点击事件。
在这里插入图片描述

接下就是怎么调节按钮自身响应事件的范围。通过重写自身的- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event来实现。

  • 扩大范围
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGRect bounds = self.bounds;
    bounds = CGRectInset(bounds, -50, -50);
    return CGRectContainsPoint(bounds, point);
}

这样子点击红色区域任意位置依然能够响应点击事件
在这里插入图片描述

  • 缩小范围
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGRect bounds = self.bounds;
    bounds = CGRectOffset(self.bounds, 50, 50);
    return CGRectContainsPoint(bounds, point);
}

在这里插入图片描述
只有点击红色区域内才能响应点击事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值