iOS触摸事件消息传递

208 阅读2分钟

本章探讨:产生触摸事件,到处理的整个过程以及对事件的控制

第一部分:找出处理事件的对象

  1. 当产生一个触摸的事件时,会首先进入UIApplication的事件收集队列;

  2. 队列保持先进先出原则

  3. 首先将最开始的事件发送给UIWindow

  4. UIWindow调用hitTest:withEvent:

hitTest:withEvent:方法大致处理流程是这样的:

首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:

若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil

若pointInside:withEvent:方法返回YES,则遍历subviews; 调用子视图的hitTest:withEvent:(子视图遍历顺序,从top到bottom)

当第一次有子视图的hitTest:withEvent:返回非空对象时,当前视图的hitTest:withEvent:就返回此对象,处理结束

当所有子视图都返回空对象时,当前视图的hitTest:withEvent:返回当前视图本身(self)

最终这个事件就交给主窗口hitTest:withEvent:方法返回的对象去处理。

第二部分:利用相应链对事件进行传递,控制,扩散

要点:

  • iOS的消息处理是,当消息被人处理后默认不再向父层传递

  • iOS判断哪个界面能接受消息是从View层级结构的父View向子View传递,即树状结构的根节点向叶子节点递归传递

  • hitTest和pointInside成对,且hitTest会调用pointInside。

响应链顺序:

UIApplicationDelegate <- UIWindow <- UIViewController <- UIView <- UIView

1、实例:将消息传递给下一个响应者

#pragma mark - touches

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

{

    NSLog(@"B - touchesBeagan..");

    // 把事件传递下去给父View或包含他的ViewController

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

}

- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent *)event

{

    NSLog(@"B - touchesCancelled..");

    // 把事件传递下去给父View或包含他的ViewController

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

}

...

self.nextResponder通过重写touchs系列方法,实现对事件的处理

2、重写hitTest拦截消息

#pragma mark - hitTest

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

{

    // 当touch point是在_btn上,则hitTest返回_btn

    CGPoint btnPointInA = [_btn convertPoint:point fromView:self];

    if([_btn pointInside:btnPointInA withEvent:event]) {

        return_btn;

    }

    // 否则,返回默认处理

    return[superhitTest:point withEvent:event];

}

3、阻止view对事件的响应:

  • 1、设置View.UserInteractionEnable=NO
  • 2、override重写pointInside
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

{

    // 本View不响应用户事件

    returnNO;

}