Hit -Test机制, 扩大UIButton的点击范围

文章目录

Hit -test 机制

过程

当用户触摸(Touch)屏幕进行交互时,系统首先要找到响应者(Responder)。系统检测到手指触摸(Touch)操作时,将Touch 以UIEvent的方式加入UIApplication事件队列中。UIApplication从事件队列中取出最新的触摸事件进行分发传递到UIWindow进行处理。UIWindow 会通过hitTest:withEvent:方法寻找触碰点所在的视图,这个过程称之为hit-test view。
hitTest 的顺序如下
UIApplication -> UIWindow -> Root View -> ··· -> subview
其伪代码如下

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    //系统默认会忽略isUserInteractionEnabled设置为NO、隐藏、或者alpha小于等于0.01的视图
    if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
        return nil;
    }
    if ([self pointInside:point withEvent:event]) {
        for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
                CGPoint childP =  [self convertPoint:point toView:childView];

            UIView *hitTestView = [subview hitTest:childP withEvent:event];
            if (hitTestView) {
                return hitTestView;
            }
        }
        return self;
    }
    return nil;
}

由以上流程可知,我们是根据pointInside:withEvent:方法来判断点击点是否在button内的
所以,可以通过重写pointInside:withEvent:的方式扩大 button 的点击范围

## 扩大button的点击范围
为了造一个全局可以使用的轮子,采用分类的方式, 重写分类的pointInside:withEvent:方法,

给分类绑定属性

```objectivec
/**
 点击区域扩大的 edgeinsets  如 赋值 UIEdgeInsetsMake(10, 20, 30, 40)
 代表向上扩大10,
 向左扩大20, 向下扩大30 ,向右扩大40
 */
@property(nonatomic, assign) UIEdgeInsets expandHitEdgeInsets;

/**
 向上扩展的点击范围
 */
@property(nonatomic, assign) CGFloat expandTopHitEdge;

/**
 向左扩展的点击范围
 */
@property(nonatomic, assign) CGFloat expandLeftHitEdge;
/**
 向下扩展的点击范围
 */
@property(nonatomic, assign) CGFloat expandBottomHitEdge;
/**
 向右扩展的点击范围
 */
@property(nonatomic, assign) CGFloat expandRightHitEdge;
/**
 是否自动扩大点击范围,默认关闭。
 如果开启,并且按钮width 或 height 小于44 ,则将相应的小于44的
 边长的点击范围设置为44
 */
@property(nonatomic, assign) BOOL isAutoHitExpand;

从写分类的方法,
注意:这里用到了 UIEdgeInsetsInsetRect
该方法可是使用一个CGRect 和一个UIEdgeInsets
生成一个新的CGRect

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGFloat top = 0;
    CGFloat left = 0;
    CGFloat bottom = 0;
    CGFloat right = 0;
    //设置默认的扩展量优先级最低
    if (self.isAutoHitExpand) {
        if (self.frame.size.height < 44) {
            top = (44 - self.frame.size.height)/2.0;
            bottom = (44 - self.frame.size.height)/2.0;
        }
        if (self.frame.size.width < 44) {
            left = (44 - self.frame.size.width)/2.0;
            right = (44 - self.frame.size.width)/2.0;
        }
    }
    //设置四个偏移量次之
    if (!UIEdgeInsetsEqualToEdgeInsets(self.expandHitEdgeInsets, UIEdgeInsetsZero)) {
        top = self.expandHitEdgeInsets.top;
        left = self.expandHitEdgeInsets.left;
        bottom = self.expandHitEdgeInsets.bottom;
        right = self.expandHitEdgeInsets.right;
    }
    //单独设置的偏移量优先级最高
    if (self.expandTopHitEdge) {
        top = self.expandTopHitEdge;
    }
    if (self.expandLeftHitEdge) {
        left = self.expandLeftHitEdge;
    }
    if (self.expandBottomHitEdge) {
        bottom = self.expandBottomHitEdge;
    }
    if (self.expandRightHitEdge) {
        right = self.expandRightHitEdge;
    }
    //添加负号使相应的内边距变为向外扩展
    UIEdgeInsets hitExpandEdge = UIEdgeInsetsMake(- top, - left, - bottom, -right);
    if(UIEdgeInsetsEqualToEdgeInsets(hitExpandEdge, UIEdgeInsetsZero) ||       !self.enabled || self.hidden) {
        return [super pointInside:point withEvent:event];
    }
    CGRect relativeFrame = self.bounds;
    CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, hitExpandEdge);
    return CGRectContainsPoint(hitFrame, point);
}


使用

    button.expandHitEdgeInsets = UIEdgeInsetsMake(20, 20, 20, 20);

这样就达到了扩大button点击范围的效果

pod ‘LBButtonExpandHitTest’

#使用方法
button.expandHitEdgeInsets = UIEdgeInsetsMake(20, 20, 20, 20);

demo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值