响应链相关知识点

术语

       hit-testing          点击检测

       responder chain   响应链


响应链可以做到的事情

通过相应链,我们可以改变用户操作的响应顺序

可以查找到视图的响应控制器



事件流程

当用户触发的一个事件发生,UIKit会创建一个包含要处理的事件信息的事件对象。然后她会将事件对象放入active app’s(应用程序对象,每个程序对应唯一一个)事件队列(为什么是队列而不是栈?因为队列是先进先出,用于保证先产生的事件先处理,栈是先进后出)。对于触摸事件,事件对象就是UIEvent对象封装的一系列触摸集合。对于动作事件,这个事件对象依赖于使用的framework和你关心哪种动作事件。

事件通过特殊的路径传递直到被传递到一个可以处理该事件的对象。首先,单例的UIApplication对象从顶层的队列中获取事件,然后分发。典型的,它将事件发送到App的关键window(key window)对象,window则为了处理该事件而发送它到初始化对象(initial object),这个初始化对像依靠事件类型。

初始化对象查找后的反馈过程如下图

For the app on the left, the event follows this path:

The initial view attempts to handle the event or message. If it can’t handle the event, it passes the event to its superview, because the initial view is not the top most view in its view controller’s view hierarchy.

The superview attempts to handle the event. If the superview can’t handle the event, it passes the event to its superview, because it is still not the top most view in the view hierarchy.

The topmost view in the view controller’s view hierarchy attempts to handle the event. If the topmost view can’t handle the event, it passes the event to its view controller.

The view controller attempts to handle the event, and if it can’t, passes the event to the window.

If the window object can’t handle the event, it passes the event to the singleton app object.

If the app object can’t handle the event, it discards the event.

The app on the right follows a slightly different path, but all event delivery paths follow these heuristics:

A view passes an event up its view controller’s view hierarchy until it reaches the topmost view.

The topmost view passes the event to its view controller.

The view controller passes the event to its topmost view’s superview.

Steps 1-3 repeat until the event reaches the root view controller.

The root view controller passes the event to the window object.

The window passes the event to the app object.

左边的情况,最初的视图接收到事件,如果它不能处理,那么它将会传递给它的父试图,它的父试图也不能处理,再传递给父试图的父试图,如果还不能处理,再传递给ViewController,也不能处理,传递给window,也不能处理,传递给Application。

右边的情况,最初的视图它不能处理时会将事件传递给它的视图控制器,视图控制器会将事件会将事件传递给视图控制器的视图的父试图,然后重复这样的过程,直到根视图控制器,也不能处理,传递给window,也不能处理,传递给Application

苹果说两种app设置的原因,但是基本都是如果初始化对象(initial object)—— 即hit-test view或者first responder —— 不处理事件,UIKit会将事件传递给responder chain的下一个responder。每个responder决定它是传递事件还是通过nextResponder方法传递给它的下一个responder。这个操作继续直到一个responder处理event或者没有responder了。

总而言之:

事件的传递和响应分两个链:

传递链:由系统向离用户最近的view传递。UIKit –> active app’s event queue –> window –> root view –>……–>lowest view

响应链:由离用户最近的view向系统传递。initial view –> super view –> …..–> view controller –> window –> Application(如果view是控制器的view,就传递给控制器;如不是,则将其传递给它的父视图 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理 如果window对象也不处理,则其将事件或消息传递给UIApplication对象 如果UIApplication也不能处理该事件或消息,则将其丢弃)

上面是原理,下面说方法:

- (UIView * _Nullable)hitTest:(CGPoint)point withEvent:(UIEvent * _Nullable)event

此方法会在视图层级结构中的每个视图上调用

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent * _Nullable)event

如果pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操作发生的位置,这个视图也就是hit-test view。

hitTest:withEvent:方法的处理流程如下:

首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;

若返回NO,则hitTest:withEvent:返回nil;

若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;

若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;

如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。

hitTest:withEvent:忽略的三种情况:

1:hidden = YES 的视图

2:userInteractionEnabled = YES 的视图

3:alpha < 0.01 的视图

如果一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常情况下对子视图在父视图之外区域的触摸操作不会被识别,因为父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写pointInside:withEvent:方法来处理这种情况。(objc_setAssociatedObject添加属性,扩展响应区域)

如果父视图需要对对哪个子视图可以响应触摸事件做特殊控制,则可以重写hitTest:withEvent:或pointInside:withEvent:方法。

如button,scrollview同为topView的子视图,但scrollview覆盖在button之上,这样在在button上的触摸操作返回的hit-test view为scrollview,button无法响应,可以修改topView的hitTest:withEvent:方法如下:

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 226,828评论 6 526
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 97,669评论 3 412
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 174,467评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,238评论 1 306
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,039评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,561评论 1 319
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,658评论 3 433
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,806评论 0 285
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,316评论 1 329
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,293评论 3 353
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,443评论 1 364
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,998评论 5 355
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,698评论 3 342
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,097评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,333评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,012评论 3 385
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,434评论 2 370

推荐阅读更多精彩内容

  • 重点参考链接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi阅读 4,476评论 0 15
  • 前言 按照时间顺序,事件的生命周期是这样的: 事件的产生和传递(事件如何从父控件传递到子控件并寻找到最合适的vie...
    欢博阅读 591评论 0 3
  • 前言: 按照时间顺序,事件的生命周期是这样的: 事件的产生和传递(事件如何从父控件传递到子控件并寻找到最合适的vi...
    reviewThis阅读 731评论 1 2
  • 在iOS开发中经常会涉及到触摸事件。本想自己总结一下,但是遇到了这篇文章,感觉总结的已经很到位,特此转载。作者:L...
    WQ_UESTC阅读 6,037评论 4 26
  • 如果你对18岁的自己说一句话,你会说什么? 我其实突然理解了我妈,因为现在的我想对当时的自己说的,都是她当时告诉我...
    爆炸宝阅读 182评论 0 0