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的生命周期不再改变,即使触摸操作后续移动到其他视图之上。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// 1.判断自己能否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil; // 2.判断点在不在当前控件上面
if (![self pointInside:point withEvent:event]) return nil; // 3.去找有没有比自己更合适的view
// 从后往前遍历自己的子控件
int count = self.subviews.count; for (int i = count - ; i >= ; i--) {
// 获取子控件
UIView *childView = self.subviews[i]; // 转换坐标系
// 把自己坐标系上的点转换成子控件做坐标系上的点
CGPoint childPoint = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childPoint withEvent:event];
// 找到最合适的view
if (fitView) {
return fitView;
} } // 没有找到比自己更合适的view
return self;
}
二.定制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按钮可以响应点击事件。
hitTest:withEvent:方法流程的更多相关文章
- 消息点击事件的响应链---hitTest:withEvent:方法
*当用户点击屏幕时,会产生一个触摸事件,系统会将触摸事件加入到 UIApplication管理事件队里中 *UIApplication 会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件 ...
- hitTest:withEvent:方法(此方法可实现点击穿透、点击下层视图功能)
此方法可实现点击穿透.点击下层视图功能 一. hitTest:withEvent:调用过程 iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,UIAppl ...
- 响应者链 hittest:withEvent: 方法的使用
关于响应者链部分的基础内容 参考http://www.cnblogs.com/wendingding/p/3795171.html 这里我要说明的是 关于- (UIView *)hitTest:(CG ...
- 关于UIView的hitTest:withEvent:方法的理解
闲来无事 观摩别人的项目 常常发现对UIView的hitTest:withEvent:方法的重写,以前也查过这个方法的用法作用,但是时间一长又忘记了.今天再次看到,就记录一下. 用户触摸屏幕后事件的传 ...
- 新浪微博客户端(59)-hitTest withEvent方法的使用说明
iOS中的触摸事件总是由最顶层的View首先得到的,当这个View得到该触摸事件的时候可以选择通过 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEv ...
- 理解点击屏幕的事件响应--->对UIView的hitTest: withEvent: 方法的理解
要理解这两个方法.先了解一下用户触摸屏幕后的事件传递过程. 当用户点击屏幕后,UIApplication 先响应事件,然后传递给UIWindow.如果window可以响应.就开始遍历window的su ...
- 点击事件处理, 以及hitTest:withEvent:实现
发送触摸事件后, 系统会将事件添加到系统UIApplication的事件管理队列中 UIApplication会在事件队列的最前端取出事件,然后分发下去,以便处理, 通常会把事件首先分发给KeyWin ...
- UITableView/UIScrollView 不能响应TouchBegin 的处理 及窥见 hitTest:withEvent:
重写touchBegin 方法是不行的,在UITableView/UIScrollView 解决方案 重写hitTest:withEvent: 在他们的子类中 - (UIView *)hitTest ...
- Patchwork(2013年)--CNV检测方法流程
文章题目:Patchwork: allele-specific copy number analysis of whole-genome sequenced tumor tissue 特点: 可以检测 ...
随机推荐
- 导入spring源码到eclipse
1.1安装Gradle 可以从http://www.gradle.org/downloads页面下载Gradle.下载后将文件解压到指定目录,我放在D:\软件\gradle-3.3,然后设置环境变量. ...
- Objective-C Runtime 运行时之六:拾遗(转载)
前面几篇基本介绍了runtime中的大部分功能,包括对类与对象.成员变量与属性.方法与消息.分类与协议的处理.runtime大部分的功能都是围绕这几点来实现的. 本章的内容并不算重点,主要针对前文中对 ...
- 接口测试:如何定位BUG的产生原因
转自公众号<QA之道> 我们从在日常功能测试过程中对UI的每一次操作说白了就是对一个或者多个接口的一次调用,接口的返回的内容(移动端一般为json)经过前端代码的处理最终展示在页面上.ht ...
- metrics实践 (metrics-spring)
这里主要介绍metrics与spring集成的使用方式. 1 添加maven依赖 <dependency> <groupId>com.ryantenney.metrics&l ...
- 关于js的那些事儿
什么是JS? JavaScript是一种基于对象(Object)和事件驱动(Event Driven),并具有相对安全性的客户端脚本语言.同时也是一种广泛用户客户端Web开发的脚本语言,常用来给HTM ...
- 第33届 MPD软件工作坊(南京站)有哪些亮点值得我们参加?
MPD软件工作坊由msup2010年创办,自创办以来,共吸引了万名的软件从业者到场参与.第33届 MPD软件工作坊(南京站)将于12月17-18日在南京召开,大会报名平台:活动家! 快捷报名通道:ht ...
- [UWP小白日记-6]页面跳转过度动画
前言 在学习中发现页面导航默认是没有过度动画的,直接就导航过去太粗暴了( ̄へ ̄),于是打算上动画结果不言而喻自己进了坑完全不懂动画,然后就是各种疯狂(´・_・`)的搜索资料看了后终于有点头绪. 再后来 ...
- 基于clip-path的任意元素的碎片拼接动效(源自鑫空间)
一.实现原理. 效果本质上是CSS3动画,就是旋转transform:rotate和位移:transform:translate,只是旋转和位移的部件是三角碎片而已.三角是使用CSS3 clip-pa ...
- EFI Shell 命令说明
EFI Shell 命令说明 引导命令 — EFI Shell 与 nPartition 引导有关的命令. autoboot 设置(查看)自动引导超时变量. bcfg 显示(或修改)驱 ...
- 绝对路径&相对路径
被绝对路径和相对路径搞疯了,好多地方不一样,从今天开始,记录下来每次关于这个问题的记录,以备查用 css文件里: 绝对路径:以"/"开头,表示从项目的根目录开始