iOS 事件响应者链的学习(也有叫 UI连锁链)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 事件响应者链的学习(也有叫 UI连锁链)相关的知识,希望对你有一定的参考价值。
当发生事件响应的时候,必须知道由谁来响应事件.在iOS中,由响应链来对事件进行响应,所有的事件响应的类都是继承于UIResponder的子类,响应链是一个由不同对象组成的层次结构,其中每个对象将依次获得响应事件消息的机会
发生触摸事件后,系统将事件假如到由UIApplication管理的事件 队列
好处:遵循第一响应原则,总会优先处理队列中排在最前面的事件.(栈是先进后出 不符合业务逻辑)
(1)事件传递(链)
1.传递链中时没有controller的,因为controller本身不具有大小的概念
2.用户的触摸事件首先会由系统截获,进行包装处理等。然后递归遍历所有的view,进行碰触测试(hitTest),直到找到可以处理事件的view
大致的过程application –> window –> root view –>……–>lowest view
网上一个很直观的解释图
(2)响应链
1.响应链中是有controller的,因为controller继承自UIResponder
2.当有view能够处理触摸事件后,开始响应事件。
系统会调用view的以下方法:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
可以多对象共同响应事件。只需要在以上方法重载中调用super的方法。
大致的过程initial view –> super view –> …..–> view controller –> window –> Application
我记得 前年被一位CTO面试的时候 问到过这个问题 ,原话大概是说”触发一个按钮,怎么截获 它的触发消息”;当时说得一塌糊涂 ,但是由于 有个创意性的问题分析回答得特别到位 ,还夸奖了我,说我有想法,他还感冒了,说要去擤鼻子 然后就没在回来 .比较遗憾的面试,其实不要估计我是女生呀,我不怕拒绝,也没说原因呢,就没有然后了.
现在想起来,估计这个”事件传递响应者链”的原理真的很重要,如今学习的更加深入,自然而然就会去讨论学习,在开发中运用起来. 真是成长如蜕啊.
举例:
其实开发中,真的好多地方可以运用到这个方法,用来截获一些信息啦,处理消息,获取对象,修改响应,或者具体知道自己实现一个方法到底该是怎样一个流程等.
需求:在cell上添加一个按钮,点击一下进入下一个导航页面.
之前通常的做法是,” [cell.btn addTarget: blabla ]” 写在视图控制器里面 ,因为这样很好的调用到viewController.
现在知道了事件响应者链的原理 就利用这个机制解决一下吧
2.1首先创建一个UIView 类别 扩展 一个实例方法 根据"事件响应者链原理" :判读UIView上的点击事件,如果已经传递到了UIViewController,则就进行处理。获取这个视图控制器.
// // UIView+EventLink.h // TableViewDemo // // Created by HF on 16/2/26. // Copyright © 2016年 HF-zhjh. All rights reserved. // #import <UIKit/UIKit.h> @interface UIView (EventLink) -(UIViewController *)viewController; @end // // UIView+EventLink.m // TableViewDemo // // Created by HF on 16/2/26. // Copyright © 2016年 HF-zhjh. All rights reserved. // #import "UIView+EventLink.h" @implementation UIView (EventLink) //为UIView扩展一个方法,用于响应事件链 -(UIViewController *)viewController{ UIResponder *nexRes=[self nextResponder]; do { //判读当前的响应者是否UIViewController if ([nexRes isKindOfClass:[UIViewController class]]) { //是否直接处理 return (UIViewController*)nexRes; }else{ //否则继续寻找 nexRes=[nexRes nextResponder]; } } while (nexRes!=nil); return nil; } @end
通过为UIView扩展一个分类(类别)方法之后,我们就可以在Cell中调用分类方法(viewController)处理事件响应了。
//按钮事件
//UITableViewCell 继承于UIView 所以 现在 cell 多了一个属性 就是 viewController 可以直接用了
//其实还算是很方便 可读性也很高
-(void)buttonAction:(UIButton *)btn{ //使用事件响应者 UIViewController *view=[[UIViewController alloc] init]; [self.viewController.navigationController pushViewController:view animated:YES]; [view release]; }
(3)几种无法接受触摸事件的情况
1.不接收用户交互
userInteractionEnabled = NO
2.隐藏
hidden = YES
3.透明
alpha = 0.0 ~ 0.01
提示:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的
以上是关于iOS 事件响应者链的学习(也有叫 UI连锁链)的主要内容,如果未能解决你的问题,请参考以下文章