当前位置: 首页 > news >正文

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

相关文章:

  • Flutter 中的 SliverCrossAxisExpanded 小部件:全面指南
  • 零基础入门篇①⑥ Python可变序列类型--字典
  • Webrtc支持HEVC之FFMPEG支持HEVC编解码(一)
  • 【Python如何将EXCEL拆分】
  • 精准检测,安全无忧:安全阀检测实践指南
  • 单片机控制语音芯片的录放音系统的设计
  • C语言之旅:探索单链表
  • TalkingData数据统计:洞察数字世界的关键工具
  • Shell编程之条件语句
  • adb的常见操作和命令
  • OpenAI 再次刷新认知边界:GPT-4 颠覆语音助手市场,流畅度直逼真人互动?
  • 革新风暴来袭:报事报修系统小程序如何重塑报事报修体验?
  • 操作系统|代表进程运行状态的各寄存器
  • 搭建基于Django的博客系统数据库迁移从Sqlite3到MySQL(四)
  • CCF-GESP 等级考试 2023年6月认证C++四级真题解析
  • [ JavaScript ] 数据结构与算法 —— 链表
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • Angular 4.x 动态创建组件
  • Asm.js的简单介绍
  • Git学习与使用心得(1)—— 初始化
  • MYSQL 的 IF 函数
  • MySQL几个简单SQL的优化
  • Python学习之路16-使用API
  • Solarized Scheme
  • const的用法,特别是用在函数前面与后面的区别
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • # 安徽锐锋科技IDMS系统简介
  • #大学#套接字
  • (2)MFC+openGL单文档框架glFrame
  • (3)(3.5) 遥测无线电区域条例
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (接口封装)
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .NET BackgroundWorker
  • .NET Core 中插件式开发实现
  • .net FrameWork简介,数组,枚举
  • .NET 某和OA办公系统全局绕过漏洞分析
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .NET/C# 使窗口永不获得焦点
  • .NET处理HTTP请求
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • @font-face 用字体画图标
  • @Resource和@Autowired的区别
  • @Service注解让spring找到你的Service bean
  • [ vulhub漏洞复现篇 ] AppWeb认证绕过漏洞(CVE-2018-8715)
  • [ajaxupload] - 上传文件同时附件参数值
  • [Algorithm][动态规划][简单多状态DP问题][按摩师][打家劫舍Ⅱ][删除并获得点数][粉刷房子]详细讲解
  • [BZOJ1008][HNOI2008]越狱
  • [C++]C++类基本语法
  • [GN] 设计模式——面向对象设计原则概述
  • [hive] 窗口函数 ROW_NUMBER()
  • [Latex] \bibitem{} | .bbl 格式参考文献转换与获得
  • [Linux] Ubuntu install Miniconda
  • [one_demo_8]十进制转二进制