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以及它的子控件默认是不能接收触摸事件的

原文地址:https://www.cnblogs.com/someonelikeyou/p/5220778.html