[New learn]响应者链机制介绍
1.简介
测试代码库:https://github.com/xufeng79x/EventHandler
响应者链是系统寻找事件相应者的一个路径,他是同touch事件的Hit-testing过程具有同等地位的事件寻主过程。
此路径开始于firstResponder结束于单例application。事件首先会让firstResponder对象去处理,如果他无法处理则会向其nextResponder对象转发事件
当所有对象都无法处理事件后将最后转发到application处并最终忽略该事件。
2.响应者链的结构
响应者链中的对象必须都是继承自UIResponder的,在UIResponder类中如下属性描绘着响应者链结构信息:
Managing the Responder Chain
canBecomeFirstResponder
方法来返回YES
.becomeFirstResponder
方法. 如果可以,需要可以自身能够进行调用。becomeFirstResponder等方法必须要在响应者链的确定后才能调用,比如能够在viewDidAppear:方法中调用起效,而不能再viewWillAppear:中调用。
canBecomeFirstResponder
方法来返回YES
.但是并不需要去覆盖becomeFirstResponder方法。当然if ([super becomeFirstResponder]) { // 其他功能代码 }
Touch events. If the hit-test view cannot handle a touch event, the event is passed up a chain of responders that starts with the hit-test view.
- --》触摸事件。如果hit-test view没有处理触摸事件,则这些事件将从以hit-test view为起点的响应者链进行处理。
Motion events. To handle shake-motion events with UIKit, the first responder must implement either the
motionBegan:withEvent:
ormotionEnded:withEvent:
method of theUIResponder
class, as described in Detecting Shake-Motion Events with UIEvent.- --》运动事件。如果firstResponder要想处理运动事件,则必须实现
motionBegan:withEvent:或者motionEnded:withEvent:方法,详细说明见Detecting Shake-Motion Events with UIEvent.
Remote control events. To handle remote control events, the first responder must implement the
remoteControlReceivedWithEvent:
method of theUIResponder
class.- --》远程事件。为了处理远程事件,firstResponder必须实现
remoteControlReceivedWithEvent:方法。
Action messages. When the user manipulates a control, such as a button or switch, and the target for the action method is
nil
, the message is sent through a chain of responders starting with the control view.- --》功能消息。当用户操作一个control控件,比如按钮或者开关控件,如果为设置对应的action处理方法,那么这些事件将会被传递给以当前control控件为起点的响应者链去处理。
Editing-menu messages. When a user taps the commands of the editing menu, iOS uses a responder chain to find an object that implements the necessary methods (such as
cut:
,copy:
, andpaste:
). For more information, see Displaying and Managing the Edit Menuand the sample code project, CopyPasteTile.- --》编辑菜单选择消息。当用户触发了编辑菜单命令,IOS通过响应者链去发现实现了必要方法的对象(诸如:cut:,copy:和paste:)。详细可参考Displaying and Managing the Edit Menu和样例代码工程CopyPasteTile
Text editing. When a user taps a text field or a text view, that view automatically becomes the first responder. By default, the virtual keyboard appears and the text field or text view becomes the focus of editing. You can display a custom input view instead of the keyboard if it’s appropriate for your app. You can also add a custom input view to any responder object. For more information, see Custom Views for Data Input.
- --》文本编辑。当用户去点击文本编辑区域或者显示文本输入控件,这个控件就自动变成了firstResponder。默认地,虚拟键盘将会弹出。你可以使用自定义的输入方式来取代默认键盘。详细可参考Custom Views for Data Input
UIKit框架自动帮助我们将文本控件设置为firstResponder,但是对于其他对象来说需要去明确地实现becomeFirstResponder方法等。
5.响应者链的事件传递方式
如果事件当前对象(hit-test view或者第一相应者)不能处理事件的时候,UIKit框架将此事件传递给当前对象的nextResponder指向的对象。每一个响应者都将决定是否自己处理还是将事件继续传递给它通过nextResponder属性指向的想一个响应者直到有对象能够处理事件或者传递到链表结尾(application对象)。
通常事件当前对象是一个view。事件当前对象首先获得处理事件的机会。下面的图直观的解释了两种配置的事件传递方式。不同的配置会有不同的事件传递路径但是原理都是一样的。
对于左边的应用的事件传递路径如下:
事件当前view接受的事件或者方法。如果他不能够处理,他将事件传递给它的父view。
- 父view尝试去处理事件。如果父view还是不能处理此事件,他将事件传递给它的父view。
- 就这样直到将事件传递给controller的顶层view。如果顶层view还是不能处理该事件,顶层view会将事件传递给controller。
- controller尝试去处理事件,如果他也不能处理,则将事件传递给window。
- 如果window对象依然不能处理事件,则将事件转发给单例的application对象。
- 如果app对象不能处理事件,则将事件抛弃。
右边的应用的事件传递路径稍微有点不一样,如下:
在不能被处理的情况下事件将会被传递给当前controller的顶层view。
当前controller的顶层view不能处理就传递给他所在的controller。
当前controller将事件传递给他的顶层View的父view。
步骤1-3将会不断的循环知道找到根controller。
根controller将事件传递给window对象。
window对象将事件传递给app对象。
重要: 如果你自定义实现了一个view去处理事件,当发生你不关心的事件时候,不要在代码中直接去使用nextResponder属性直接调用响应者对象。你应该直接调动父类的事件处理方法,将事件参数直接传递给父类的事件处理方法。这样UIKit框架将自动会在响应者链中自动的去寻找事件的处理者。
6.思考
上面balabala说了一顿,纯粹是对于官方文档的翻译,但是即使读懂了官方文档依然会产生很多疑问。
疑问一:view在什么情况下能够变成第一响应者?条件是什么?
疑问二:如果一个touch事件发生后事件当前对象并不处理,他会正确传递给他的父view吗?要是此时认为设定firstResponder是其他view会出现什么结果呢?
上述纯粹是一个初学者的疑问,按照惯例我也将做一些测试区释疑这些问题。

#import "XFFirstResponder.h" @implementation XFFirstResponder -(BOOL) canBecomeFirstResponder { return YES; }// 打印按钮处理方法,用于测试定位第一响应者是谁 -(void)pressPrint { NSLog(@"do pressPrint,I am in %@", self.name); } // 处理触摸事件 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 打印当前对象处理结果 NSLog(@"do touchBegan, I am in %@", self.name); // 继续执行父类方法,由此将得出整个响应者链路径 [super touchesBegan:touches withEvent:event]; }
7.3 测试主方法设定如下:
@implementation ViewController -(void)viewDidLoad { // 将view设定名称便于区分 self.viewA.name = @"viewA"; self.viewB.name = @"viewB"; self.viewC.name = @"viewC"; self.viewD.name = @"viewD"; // 将button设置action,target设置为nil,这将导致此事件去像第一相应者发送事件,便于我们定位第一响应者是谁 [self.button addTarget:nil action:@selector(pressPrint) forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside]; }
-(BOOL)canBecomeFirstResponder { return YES; }
然后在viewDidAppear方法中去调用想要成为第一响应者的becomeFirstResponder方法即可。
如在本例中将viewD设定我第一响应者
-(void) viewDidAppear:(BOOL)animated { [self.viewD becomeFirstResponder]; }
然后去触发按钮事件:
// 将button设置action,target设置为nil,这将导致此事件去像第一相应者发送事件,便于我们定位第一响应者是谁 [self.button addTarget:nil action:@selector(pressPrint) forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside];
我们看到,由于按钮的target是设置为nil的,所以系统将去寻找当前第一响应者,如果第一响应者有pressPrint这个方法,那么他会调用它的pressPrint方法。而现在viewD中是实现了此方法:
// 打印按钮处理方法,用于测试定位第一响应者是谁 -(void)pressPrint { NSLog(@"do pressPrint,I am in %@", self.name); }
程序启动点击按钮,日志打印:
-- :::] do pressPrint,I am in viewD
说明,在例子中设定第一响应者成功。
疑问二:如果一个touch事件发生后事件当前对象并不处理,他会正确传递给他的父view吗?要是此时认为设定firstResponder是其他view会出现什么结果呢?
例如在本测试中,在view的实现方法中都实现了touchesBegan方法如下,他会将整触摸事件的响应者链打印出来。
// 处理触摸事件 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 打印当前对象处理结果 NSLog(@"do touchBegan, I am in %@", self.name); // 继续执行父类方法,由此将得出整个响应者链路径 [super touchesBegan:touches withEvent:event]; }
情况1:
当当前对象有能力处理事件的时候:
此时我们去点击将viewD设定为第一响应者,然后去触摸viewC,那么这个触摸事件会第一时间找第一响应者吗?
-- :::] do touchBegan, I am in viewC -- :::] do touchBegan, I am in viewB -- :::] do touchBegan, I am in viewA
情况二:
在情况一种,viewC是有能力处理触摸事件的,但是让他没有能力触发事件的时候回发生什么呢?会将事件转发给第一响应者吗?
1.创建NoToouchEventView类,依附于viewC,这个类是没有touch事件的。
-- :::] do touchBegan, I am in viewB -- :::] do touchBegan, I am in viewA
可以看到,虽然viewD还是第一响应者,但是在touch事件中,依然按照hit-testing的机制在转发事件,并不理睬响应者链。
[New learn]响应者链机制介绍的更多相关文章
- iOS响应者链和事件传递机制
原文来自:http://www.cnblogs.com/zhw511006/p/3517248.html 响应者链(Responder Chain) 通常,一个iOS应用中,在一块屏幕上通常有很多的U ...
- 响应者链和Hit-Test 机制
概念: 响应者 : 对用户交互动作事件进行响应的对象.响应者链:成为处理事件的响应者的先后顺序链. 1.Hit-Test 机制 当用户触摸(Touch)屏幕进行交互时,系统首先要找到响应者(Respo ...
- hit-testing机制介绍
1.简介 寻找处理触摸事件的view的过程为hit-testing,找到的能够处理触摸事件的view叫做hit-test view. 2.机制介绍 假设下图为我们的手机屏幕,当我们假设点击了view ...
- Cocoa Touch事件处理流程--响应者链
Cocoa Touch事件处理流程--响应者链 作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9264335 转载请注明 ...
- iOS利用响应链机制点击tableview空白处关闭键盘-可以作为参考
http://www.jianshu.com/p/9717b792599c 是原文地址 处理关闭键盘的做法一般分为两种:1.放弃第一响应者身份:2.当前视图结束编辑.通常情况下只要我们在合适的时机 ...
- Responder一点也不神秘————iOS用户响应者链完全剖析
一.事件分类 对于IOS设备用户来说,他们操作设备的方式主要有三种:触摸屏幕.晃动设备.通过遥控设施控制设备.对应的事件类型有以下三种: 1.触屏事件(Touch Event) 2.运动事件(Moti ...
- iOS Responder Chain 响应者链
一.事件分类 对于IOS设备用户来说,他们操作设备的方式主要有三种:触摸屏幕.晃动设备.通过遥控设施控制设备.对应的事件类型有以下三种: 1.触屏事件(Touch Event) 2.运动事件(Moti ...
- 响应者链UIResponder-扩大UIButton的点击范围
在开发中,我们经常看到有按钮等的点击,会出现响应事件.按钮->view->ViewController->UIWindow->UIApplication,这就形成了一个响应链. ...
- AELF(ELF)区块链项目介绍
AELF(ELF)区块链项目介绍,Aelf在交易所上的名称是ELF,最近涨了不少了,可以长期关注逢低建仓,根据自身情况可以适当轻仓配置点.AELF总结下来就是希望打造一个B2B的区块链开放式OS系统. ...
随机推荐
- Codeforces Gym 101142 G Gangsters in Central City (lca+dfs序+树状数组+set)
题意: 树的根节点为水源,编号为 1 .给定编号为 2, 3, 4, …, n 的点的父节点.已知只有叶子节点都是房子. 有 q 个操作,每个操作可以是下列两者之一: + v ,表示编号为 v 的房子 ...
- HDOJ(HDU).1003 Max Sum (DP)
HDOJ(HDU).1003 Max Sum (DP) 点我挑战题目 算法学习-–动态规划初探 题意分析 给出一段数字序列,求出最大连续子段和.典型的动态规划问题. 用数组a表示存储的数字序列,sum ...
- 【简单算法】17.字符串转整数(atoi)
题目: 实现 atoi,将字符串转为整数. 在找到第一个非空字符之前,需要移除掉字符串中的空格字符.如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即为 ...
- Linux之同步互斥阻塞20160703
主要介绍一下Linux下的互斥与阻塞方面的知识: 1. 原子操作 原子操作指的是在执行过程中不会被别的代码路径所中断的操作. 常用原子操作函数举例: atomic_t v = ATOMIC_INIT( ...
- POJ1679:The Unique MST(最小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 38430 Accepted: 14045 ...
- POJ---3463 Sightseeing 记录最短路和次短路的条数
Sightseeing Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9247 Accepted: 3242 Descr ...
- [ 转载]Tomcat7 catalina.out 日志分割
http://m.blog.csdn.net/blog/mark_qi/8864644 最近由于工作需要,tomcat 的catalina.out文件的不断扩大,导致系统磁盘空间边变小,而且管理也难于 ...
- js ejs for语句的第二种遍历用法
var A = {a:1,b:2,c:3,d:"hello world"}; for(var k in A) { console.log(k,A[k]); var h = new ...
- 如何把自己写的python程序给别人用
这里讲的给别人用,不是指将你的代码开源,也不是指给另一个程序员用..... 前段时间写了个程序,输入URP学生系统的账号和密码,输出课表.绩点之类的信息,想给同学用,但是总不能叫别人也去装python ...
- [LeetCode] 13. Roman to Integer ☆☆
Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 t ...