hitTest:withEvent:方法流程
此方法可实现点击穿透、点击下层视图功能。
一. hitTest:withEvent:调用过程
iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,UIApplication会从事件队列中取出触摸事件并传递给key window(当前接收用户事件的窗口)处理,window对象首先会使用hitTest:withEvent:方法寻找此次Touch操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,称之为hit-test view。
window对象会在首先在view hierarchy的顶级view上调用hitTest:withEvent:,此方法会在视图层级结构中的每个视图上调用pointInside:withEvent:,如果pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操作发生的位置,这个视图也就是hit-test view。
hitTest:withEvent:方法的处理流程如下:
- 首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
- 若返回NO,则返回nil;
- 若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;
- 若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
- 如所有子视图都返回非,则方法返回自身(self)。
hitTest:withEvent:方法忽略隐藏(hidden=YES)的视图,禁止用户操作(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。如果一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常情况下对子视图在父视图之外区域的触摸操作不会被识别,因为父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写pointInside:withEvent:方法来处理这种情况。
对于每个触摸操作都会有一个UITouch对象,UITouch对象用来表示一个触摸操作,即一个手指在屏幕上按下、移动、离开的整个过程。UITouch对象在触摸操作的过程中在不断变化,所以在使用UITouch对象时,不能直接retain,而需要使用其他手段存储UITouch的内部信息。UITouch对象有一个view属性,表示此触摸操作初始发生所在的视图,即上面检测到的hit-test view,此属性在UITouch的生命周期不再改变,即使触摸操作后续移动到其他视图之上。
1 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 2 { 3 // 1.判断自己能否接收事件 4 if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil; 5 6 // 2.判断点在不在当前控件上面 7 if (![self pointInside:point withEvent:event]) return nil; 8 9 // 3.去找有没有比自己更合适的view 10 // 从后往前遍历自己的子控件 11 int count = self.subviews.count; 12 13 for (int i = count - 1; i >= 0; i--) { 14 // 获取子控件 15 UIView *childView = self.subviews[i]; 16 17 // 转换坐标系 18 // 把自己坐标系上的点转换成子控件做坐标系上的点 19 CGPoint childPoint = [self convertPoint:point toView:childView]; 20 21 UIView *fitView = [childView hitTest:childPoint withEvent:event]; 22 // 找到最合适的view 23 if (fitView) { 24 return fitView; 25 } 26 27 } 28 29 // 没有找到比自己更合适的view 30 return self; 31 }
二.定制hitTest:withEvent:方法
如果父视图需要对对哪个子视图可以响应触摸事件做特殊控制,则可以重写hitTest:withEvent:或pointInside:withEvent:方法。
这里有几个例子:
- Hacking the responder chain
- 在此例子中button,scrollview同为topView的子视图,但scrollview覆盖在button之上,这样在在button上的触摸操作返回的hit-test view为scrollview,button无法响应,可以修改topView的方法如下:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { - UIView *result = [super hitTest:point withEvent:event];
- CGPoint buttonPoint = [underButton convertPoint:point fromView:self];
- if ([underButton pointInside:buttonPoint withEvent:event]) {
- return underButton;
- }
- return result;
- }
这样如果触摸点在button的范围内,返回hittestView为button,从button按钮可以响应点击事件。
转载于:https://www.cnblogs.com/H7N9/p/4943826.html
hitTest:withEvent:方法流程相关推荐
- -[UIView hitTest:withEvent:] 方法总结
现象 -hitTest:withEvent: 方法内部会调用 -pointInside:withEvent: 方法. 一次点击会触发两次 -hitTest:withEvent: 方法. -pointI ...
- 理解点击屏幕的事件响应---对UIView的hitTest: withEvent: 方法的理解
要理解这两个方法.先了解一下用户触摸屏幕后的事件传递过程. 当用户点击屏幕后,UIApplication 先响应事件,然后传递给UIWindow.如果window可以响应.就开始遍历window的su ...
- 2021-12-01 WPF上位机 103-西门子S7协议之V区,DB区读数据方法流程解析
文章目录 前言 一.西门子S7协议之V区,DB区读数据方法流程解析 二.使用步骤 1.读取数据 总结 前言 随着人工智能的不断发展,物联网这门技术也越来越重要,很多人都开启了物联网学习,本文就介绍了物 ...
- Vue3/ Vue3 组件通讯 -- 子传父 方法流程 总结
一 .Vue3 组件通讯 -- 子传父 方法流程 1. 首先子组件通过 defineEmit 写入传递事件名 并 定义变量名 const 变量名one = defineEmit([' 传递事件名']) ...
- 没有无线网卡的服务器开wifi,电脑没无线网卡怎么开wifi热点 160wifi一键上网方法流程...
160wifi一键上网方法流程: 现在市面上,无论是台式机还是笔记本,都带有内置无线网卡,但其利用率却不高,一台机器的无线网卡,只能为一台机器提供无线wifi网络.其实你的内置无线网卡,比你想象的更有 ...
- gear s3刷android wear,三星gear s3怎么刷机教程 三星gear s3刷机方法流程
三星gear s3刷机方法流程: 在今年九月在IFA电子展正式亮相的三星Gear S3在本月即将在国内开卖,目前不少电商的商家已经为这款新品进行预热,从电商的价格来看这两款定位不同的智能手表(经典款/ ...
- 2022-02-17 WPF上位机 120-三菱PLC协议之读写方法流程解析
文章目录 前言 一.三菱PLC协议之读写方法流程解析 二.使用步骤 前言 随着人工智能的不断发展,物联网这门技术也越来越重要,很多人都开启了物联网学习,本文就介绍了物联网的三菱PLC协议. 提示:以下 ...
- 2021-12-20 WPF上位机 120-三菱PLC协议之读写方法流程解析
文章目录 前言 一.三菱PLC协议之读写方法流程解析 二.使用步骤 前言 随着人工智能的不断发展,物联网这门技术也越来越重要,很多人都开启了物联网学习,本文就介绍了物联网的三菱PLC协议. 提示:以下 ...
- 2021-11-27 WPF上位机 102-西门子S7协议之I区读数据方法流程解析
文章目录 前言 一.西门子S7协议之I区读数据方法流程解析 二.使用步骤 1.modbus读取数据代码 2.读取数据 总结 前言 随着人工智能的不断发展,物联网这门技术也越来越重要,很多人都开启了物联 ...
最新文章
- 线程编程常见API简介(中)
- PHP全栈开发(八):CSS Ⅸ dispaly visibility
- Query Specific Fusion for Image Retrival 学习日常
- ASP.NET MVC 2示例Tailspin Travel UI层分析
- 2018 年度总结 —— 缘见
- Max retries exceeded with url 解决方案
- windows下yolov4-deepsort项目tensorflowGPU版本配置+项目实战
- 微信支付 支付成功后不跳转 ecshop微信支付 如下操作即可
- eltable 无数据文案修改_el-table的二次封装详细版(一)
- ElasticSearch介绍ES客户端IK分词器Kibana安装
- 投屏设置 android,上班摸鱼神器 Anlink安卓手机投屏操作体验
- “我玩某宝第1年,还清所有欠款”:会挣钱的人,都活成什么样 ?
- javac提示信息变成英文
- 解魔方神器开源啦!摄像头看一眼,就能还原全步骤
- 苹果手机连接电脑服务器传文件,还在羡慕苹果电脑隔空操作?windows的这个骚操作,3秒即可传文件...
- 我的世界java蜜蜂_在最新的《我的世界》Java版更新中 蜜蜂是所有的热点
- java i18n utf_struts2.0乱码 在struts.xml里面设置struts.i18n.encoding=utf-8依然出现乱码是怎么回事呀...
- Python+GDAL面数据中心点提取为单独shape文件,并复制属性数据
- 操作系统常见面试题(2022年最新版)
- 包管理工具,npm、yarn、pnpm
热门文章
- ggplot01:R语言坐标轴离散、连续与图例离散连续的区分
- linux共享磁盘给指定ip,Linux 磁盘挂载和mount共享
- php类对象无法转还子符串问题,php – 类stdClass的对象无法转换为字符串
- linux查看服务依赖关系,服务管理(1)
- html文章整体居中,div居中与div内容居中
- 手绘线条一直画不直_我学素描,线条画不直怎么办啊?
- yolov5检测完不显示框和标注
- 怎么设置表格根据窗口自动调整_Word排版技巧之表格美化,你值得拥有!
- jQuery的选择器
- top---报错terminal is not big enough