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链接

相关推荐
陈皮话梅糖@5 小时前
iOS 集成ffmpeg
ios·ffmpeg
allanGold5 小时前
【xcode 16.2】升级xcode后mac端flutter版的sentry报错
macos·xcode16.2
幽夜落雨6 小时前
ios老版本应用安装方法
ios
gxhlh12 小时前
局域网中 Windows 与 Mac 互相远程连接的最佳方案
windows·macos
宏基骑士12 小时前
mac 电脑上安装adb命令
macos·adb
胖虎113 小时前
实现 iOS 自定义高斯模糊文字效果的 UILabel(文末有Demo)
ios·高斯模糊文字·模糊文字
水银嘻嘻18 小时前
【Mac】Python相关知识经验
开发语言·python·macos
梦魇梦狸º1 天前
mac 配置 python 环境变量
chrome·python·macos
丁总学Java2 天前
macOS如何进入 Application Support 目录(cd: string not in pwd: Application)
macos
qdprobot2 天前
Mixly米思齐1.0 2.0 3.0 软件windows版本MAC苹果电脑系统安装使用常见问题与解决
windows·macos