• iOS hitTest 机制用处之二-----使用pointInside方法


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

    由上面的hittest机制可以知道,如果我们想扩大一个视图的点击范围,或者让一个超出父视图的子视图可以点击,我们既可以通过重写hittest方法实现,即在hittest 方法中去掉pointinside方法的判断,同时也可以通过重写pointinside 方法来实现
    重写任何一个方法都可以实现这两种功能
    以前写过通过hittest方法来实现的文章 点击这里
    所以这里我们只介绍通过重写pointinside 方法分别实现扩大点击范围和超出父视图可以点击
    其实不管是重写hittest 或者是 重写point inside ,不管是
    扩大点击范围,或者是超出父视图可以点击,本质上都是
    修改系统的判断一个点是否在视图的的判断逻辑

    重写hittest, 扩大点击范围我们就去掉系统直接掉用pointinside方法,
    改为判断扩大后的rect 是否包含point,超出父视图可以点击
    我们就直接将point转换为相对于子视图的point,然后让子视图自己掉用hittest, 看是否返回view
    代码如下

    //
    //  LBHittestButton.m
    //  TEXT
    //
    //  Created by mac on 2024/6/1.
    //  Copyright © 2024 刘博. All rights reserved.
    //
    
    #import "LBHittestButton.h"
    
    @interface LBHittestButton ()
    
    @property (nonatomic, strong) UIButton *subButton;
    
    
    @end
    
    @implementation LBHittestButton
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        if (self = [super initWithFrame:frame]) {
            [self addSubview:self.subButton];
        }
        return self;
    }
    
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        CGPoint pointInSubbutton = [self convertPoint:point toView:self.subButton];
        if ([self.subButton hitTest:pointInSubbutton withEvent:event]) {
            return [self.subButton hitTest:pointInSubbutton withEvent:event];
        }
        
        CGRect rect = UIEdgeInsetsInsetRect(self.bounds, self.expandEdgeInset);
        if (CGRectContainsPoint(rect, point)) {
            return self;
        }
        return [super hitTest:point withEvent:event];
    }
    
    - (void)clickSubButton
    {
        NSLog(@"哈哈哈点击小按钮小按钮");
    }
    
    #pragma mark - lazy load
    
    - (UIButton *)subButton
    {
        if (!_subButton) {
            _subButton = [UIButton buttonWithType:UIButtonTypeCustom];
            _subButton.frame = CGRectMake(100, 140, 40, 40);
            _subButton.backgroundColor = [UIColor redColor];
            [_subButton addTarget:self action:@selector(clickSubButton) forControlEvents:UIControlEventTouchUpInside];
        }
        return _subButton;
    }
    
    @end
    
    

    重写point inside ,如果是扩大点击范围,我们就判断新的rect是否包含point, 如果是子视图超出父视图可以点击,我们就将point转换为相对于子视图的point,然后判断是否在子视图中
    代码如下

    //
    //  LBHittestButton.m
    //  LBHitTestDemo
    //
    //  Created by mac on 2024/6/2.
    //
    
    #import "LBHittestButton.h"
    
    @interface LBHittestButton ()
    
    @property (nonatomic, strong) UIButton *subButton;
    
    @end
    
    @implementation LBHittestButton
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        if (self = [super initWithFrame:frame]) {
            [self addSubview:self.subButton];
        }
        return self;
    }
    
    - (void)subButtonClick
    {
        NSLog(@"点击了子视图");
    }
    
    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
        CGPoint point2 = [self convertPoint:point toView:self.subButton];
        if ([self.subButton pointInside:point2 withEvent:event]) {
            return YES;
        }
        
        CGRect rect2 = UIEdgeInsetsInsetRect(self.bounds, self.expandEdgeInsets);
        if (CGRectContainsPoint(rect2, point)) {
            return YES;
        }
        return [super pointInside:point withEvent:event];
    }
    
    #pragma mark - lazy load
    
    - (UIButton *)subButton
    {
        if (!_subButton) {
            _subButton = [UIButton buttonWithType:UIButtonTypeCustom];
            _subButton.frame = CGRectMake(100, 200, 40, 40);
            _subButton.backgroundColor = [UIColor cyanColor];
            [_subButton addTarget:self action:@selector(subButtonClick) forControlEvents:UIControlEventTouchUpInside];
        }
        return _subButton;
    }
    
    @end
    
    

    demo链接

  • 相关阅读:
    【桶计数】面试题 01.02. 判定是否互为字符重排
    【解刊】IEEE(Trans)系列,CCF-A类顶刊,国人友好,无需版面费!
    Redis缓存的使用
    信通传媒携各家虚商领袖,走进九牛汇
    linux 下代码检查工具部署使用
    IP-guard客户端WINDOWS的打包方式
    【AXI】解读AXI协议事务属性(Transaction Attributes)
    Arduino驱动BNO055 10轴绝对定向传感器(惯性测量传感器篇)
    1800个编程语言必备英语词汇整理(PDF版分享给你 )
    分享一些常用的小程序免费源码
  • 原文地址:https://blog.csdn.net/LIUXIAOXIAOBO/article/details/139382120