文档章节

UI控件无法响应点击等事件的探索

法斗斗
 法斗斗
发布于 2016/05/11 14:14
字数 1381
阅读 62
收藏 0

UI控件无法响应点击等事件的探索

一、响应者链

关于响应者链,有如下一段介绍:每一个应用有一个响应者链,我们的视图结构是一个N叉树(一个视图可以有多个子视图,一个子视图同一时刻只有一个父视图),而每一个继承UIResponder的对象都可以在这个N叉树中扮演一个节点。当叶节点成为最高响应者的时候,从这个叶节点开始往其父节点开始追朔出一条链,那么对于这一个叶节点来讲,这一条链就是当前的响应者链。响应者链将系统捕获到的UIEvent与UITouch从叶节点开始层层向下分发,期间可以选择停止分发,也可以选择继续向下分发。

那,我要是告诉你们,响应者链就是上面那段话介绍的,估计你们得拿板砖拍我了。这等于没说。别急,先来举个栗子:

我用SingleView模板创建了一个新的工程,它的主Window上只有一个UIViewController,其View之上有一个Button。这个项目中所有UIResponder的子类所构成的N叉树为这样的结构:

b26Nri.jpg!web

那么他看起来并不像N叉树,但是不代表者不是一颗N叉树,当我们项目复杂之后,这个View可不可以有多个UIButton节点?所以他就是一棵树。

实际上我们要把这棵树写完整,应该还要算上UIButton的UILabel和UIImageView,因为他们也是UIReponder的子类。这里先不考虑了。

所以我们尝试在任意地方打印这个Button的nextReponder对象。nextResponder对象是UIReponder类的实例方法,它会返回任意对象在树中的上一个响应者实例:

 
  1. NSLog(@"%@", self.btn.nextResponder);

控制台输出信息如下:

<UIView: 0x7f8973e92b60; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f8973e92ee0>>

咱们可以一直打印下去,获取下一个Responder的下一个Responder,依次获取的响应者是:

<ViewController: 0x7f8973c2ccf0>

(null)

为什么这里ViewController没有父亲呢?

注意这句代码我是写在ViewDidLoad中,而我们知道这个方法的生命周期比较早,所以我们换个地方写或者延迟一段时间再打印,两种方法都可以得到结果(由此可以推理出我们响应者树的构造过程是在ViewDidLoad周期中来完成的,这个函数会将当前实例的构成的响应者子树合并到我们整个根树中):

 
  1. double delayInSeconds = 2.0;
  2. dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
  3. dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
  4. NSLog(@"%@",self.btn.nextResponder.nextResponder.nextResponder);
  5. NSLog(@"%@",self.btn.nextResponder.nextResponder.nextResponder.nextResponder);
  6. NSLog(@"%@",self.btn.nextResponder.nextResponder.nextResponder.nextResponder.nextResponder);
  7. NSLog(@"%@",self.btn.nextResponder.nextResponder.nextResponder.nextResponder.nextResponder.nextResponder);
  8. });

最后获取就是上边给出的那幅图的样子了。那说了这么多,这个Responder到底有什么用呢?

在AppDelegate里面重写touchesBegan方法:

 
  1. -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  2. {
  3. NSLog(@"AppDelegate接收到触摸事件");
  4. }

在ViewController里面也重写:

 
  1. -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  2. {
  3. [super touchesBegan:touches withEvent:event];
  4. NSLog(@"ViewController接收到触摸事件");
  5. }

用户手指触摸到了UIView上,由于我们没有重写UIView的UITouchEvent,所以他里面和super执行的一样的,将该事件继续分发到UIViewController;

UIViewController的TouchBegan被我们重写了,如果我们不super,那么我们在这里写响应代码。事件到这里就不继续分发了。可想而知,UIViewController祖先节点:UIWindow,UIApplication,AppDelegate都无权被分发此事件。

如果我们super了TouchBegan,那么此次触摸事件由

ViewController分发给UIWindow,

UIWindow继而分发给UIApplication,

UIApplication再分发给AppDelegate,

于是我们在ViewController和appDelegate的touchBegan方法中都捕获到了这次事件。

但是这只是处理点击事件顺序,也即是确认了第一响应者之后的处理流程。

那寻找第一响应者的流程是怎样的呢。

其实就是逆向走一遍,当沿着这条响应者链找到了第一响应者,那么就会返回事件给自己的nextResponder去处理,直到appDelegate。

下面回到咱们的主题,既然点击按钮,没有触发点击事件,响应者链有很大嫌疑。

为什么这么说呢??

我问大家,如果你点击完按钮之后,没有找到第一响应者,或者是第一响应者找错了,还会调用button的触发事件吗??显而易见。

下面列举常见的几大原因,有兴趣的同学可以去试试。

  • 按钮不在响应者链上(比如我遇到的按钮从屏幕外推入屏幕内,不响应点击事件,初步猜想是button初始位置在UIWindow外,所以不在响应者链上)
  • 按钮的点击事件被其他控件拦截(比如按钮上面有按钮,点击上面的按钮)

二、视图生命周期

这个理解起来就简单一些,比如实现按钮点击事件所在的视图控制器被回收了。但是由于按钮被添加到当前可见视图上,按钮没有被回收,所以是可见的。但是点击这个按钮却没有任何作用。

三、总结

单单是上面两个方面并不能涵盖所有的类似情况,而且这节咱们只是从UIButton入手。在具体的开发中,有很多经验所不能够解释的现象,但是上面两点一般是优先考虑的。

本文转载自:

法斗斗
粉丝 23
博文 368
码字总数 17774
作品 0
杨浦
程序员
私信 提问
如何使用 Qt 开发音视频通话应用

作者:单辉,声网 Agora 高级开发工程师。 众所周知,Qt 是一个跨平台的 C++ 图形用户界面应用程序开发框架,它具有跨平台、丰富的 API、支持 2D/3D 图形渲染、支持 OpenGL、开源等优秀的特性...

声网Agora
05/29
0
0
iOS-事件响应链的学习

前言 事件处理完整过程; 1,在手指触摸屏幕时,会产生一个事件,系统会把这个事件添加到UIApplication管理的事件队列中。 2,取出队列中最前面的事件,交给主窗口Window。 3,主窗口会逐级向...

麦兜卖鱼丸
2016/06/14
155
1
Unity4.6新UI系统初探(uGUI)

一、引言 Unity终于在即将到来的4.6版本内集成了所见即所得的UI解决方案(视频)。事实上从近几个版本开始,Unity就在为这套系统做技术扩展,以保证最终能实现较理想的UI系统。本文试图通过初步...

小姚
2014/12/24
9.9K
1
ui事件冲突,取消拦截父控件的事件拦截

当手指触摸到屏幕时,系统就会调用相应View的onTouchEvent,并传入一系列的action。当有多个层级的View时,在父层级允许的情况下,这个action会一直向下传递直到遇到最深层的View。所以touch...

Carbenson
2016/11/24
107
0
iOS开发——响应链(Responder Chain)的深入理解和代码示例(二)

响应链机制是开发中很重要的概念,在一些事件的处理中需要对响应链的传递有深入的了解,我们才能对事件的传递有更好的控制。今天我们继续来研究下响应链,并实现一个很简单的功能。示例代码已...

CHENYUFENG1991
2016/07/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周四乱弹 —— 当你简历注水但还是找到了工作

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @花间小酌 :#今日歌曲推荐# 分享成龙的单曲《男儿当自强》。 《男儿当自强》- 成龙 手机党少年们想听歌,请使劲儿戳(这里) @hxg2016 :刚在...

小小编辑
今天
3K
22
靠写代码赚钱的一些门路

作者 @mezod 译者 @josephchang10 如今,通过自己的代码去赚钱变得越来越简单,不过对很多人来说依然还是很难,因为他们不知道有哪些门路。 今天给大家分享一个精彩的 GitHub 库,这个库整理...

高级农民工
昨天
5
0
用好项目管理工具,人人都可以成为项目经理

现在市面上的项目管理工具越来越多了,但是大多数都是一些协同工具或轻量项目管理工具。如果是多团队、跨部门使用或者企业级的项目管理,从管理思想到工具运用,需要适应企业的业务流程体系,...

cs平台
昨天
13
0
只需一步,在Spring Boot中统一Restful API返回值格式与统一处理异常

统一返回值 在前后端分离大行其道的今天,有一个统一的返回值格式不仅能使我们的接口看起来更漂亮,而且还可以使前端可以统一处理很多东西,避免很多问题的产生。 比较通用的返回值格式如下:...

晓月寒丶
昨天
70
0
区块链应用到供应链上的好处和实际案例

区块链可以解决供应链中的很多问题,例如记录以及追踪产品。那么使用区块链应用到各产品供应链上到底有什么好处?猎头悬赏平台解优人才网小编给大家做个简单的分享: 使用区块链的最突出的优...

猎头悬赏平台
昨天
32
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部