iOS Responder Chain

一. UIResponder类

UIApplicationUIViewController,UIView和所有继承自UIView的UIKit类(包括UIWindow,继承自UIView)都直接或间接的继承自UIResponder,所以它们的实例都是responder object对象。

二.响应链

对于一个UIButton的响应顺序

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

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

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

[addbt addTarget:self action:@selector(btnaction:) forControlEvents:UIControlEventTouchUpInside];

响应链简单来说,就是一系列的相互关联的对象,从firstResponder开始,到application对象结束,如果firstResponder 无法响应事件,则交给nextResponder来处理,直到结束为止。

iOS系统在处理事件时,通过UIApplication对象和每个UIWindow对象的sendEvent:方法将事件分发给具体处理此事件的responder对象(对于触摸事件为hit-test view,其他事件为first responder),当具体处理此事件的responder不处理此事件时,可以通过responder chain交给上一级处理。

三  nextResponder

1、UIView的nextResponder是直接管理它的UIViewController(也就是VC.view.nextResponder=VC),如果当前View不是ViewController直接管理的View,则nextResponder是它的superView(view.nextResponder = view.superView)

2、UIViewController的nextResponder是它直接管理的View的superView(VC.nextResponder = VC.view.superView)

3、UIWindow的nextResponder是UIApplication

4、UIApplication的nextResponder是UIApplicationDelegate(官方文档说是nil)

四  nextResponder 使用

通过UIViewController的view属性可以访问到其管理的view对象,及此view的所有subviews。但是根据一个view对象,没有直接的方法可以得到管理它的viewController,但我们使用responder chain可以间接的得到,代码如下:

@implementation UIView (ParentController)
-(UIViewController*)parentController{
    UIResponder *responder = [self nextResponder];
    while (responder) {
	if ([responder isKindOfClass:[UIViewController class]]) {
		return (UIViewController*)responder;
	}
	responder = [responder nextResponder];
    }
    return nil;
}
@end

五  Touches Events 理解

我们在重写TouchesEvents的时候,如果不想让响应链继续传递,就不调用super对应的实现就可以了,但是你不想中断响应链,你就需要调用父类对应的实现。调用super的目的就是为了把事件传递给nextResponder,并且如果我们在 touchesBegan 中没有调用super,则super不会响应其他的回掉(touchesMoved/touchesEnded),但是我们需要重写所有如上所示的方法来确保我们的一切正常。touchesBegan 和 touchesEnded/touchesCancelled一定是成对出现的,这点大家可以放心。

六 杂谈

响应链能够处理很多东西,不仅仅是触摸事件。一般来说,如果我们需要一个对象去处理一个非触摸事件(摇一摇,RemoteControlEvents,调用系统的复制、粘贴框等),我们要确保该对象是UIResponder子类,如果我们要接收到事件的话,我们需要做两件事情

1、重写canBecomeFirstResponder ,并且返回YES

2、在需要的时候像该对象发送becomeFirstResponder消息。

如果你自己想自定义一个非TouchEvent的事件,当需要继续传递事件的话,切记不要在实现内直接显示的调用nextResponder的对应方法, 而是直接调用super对应的方法来让这个事件继续分发到响应链。

有继承关系用super;btn1:btn:UIButton​​​​​​​ 或者使用分类category

btn1

[super touchesBegan:touches withEvent:event]; //btn1->btn->UIButton,

//[btn addSubview:btn1];用self.nextResponder //btn1->btn->self.view ->UIViewController

   [self.nextResponder touchesBegan:touches withEvent:event];

UIImageView的默认是不接受点击事件的,如果想要实现如上所示效果,需要设置userInteractionEnabled=YES;

CALayer 不是UIResponder的子类,这说明CALayer(NSObject)无法响应事件,这也是UIView和CALayer的重要区别之一。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值