iOS 事件传递和响应机制
一.概述
APPs通过responder objects来接收和处理点击事件,responder
Object是UIResponder类的实例。同时UIView,UIViewController,UIApplication
也是UIResponder类的子类。
事件的传递过程就是寻找first responder的过程,传递过程是从父控件到子控件逐层寻找第一响应者(UIApplication-> window->最合适的view)。找到firstResponder之后开始进行事件响应的过程,也就是说响应链的这顺序正好和事件的传递顺序相反,从子控件沿着响应链一直到响应链末端的父控件。
二. 响应链的传递过程
1.响应链的传递过程如下图:
下图展示一个简易的APP,包含UILabel, UITextFileld, UIButton,UIView,UIViewController。如图示,响应链从上向下传递,传递到能响应的层级截止,如均无发响应这个事件,相当于系统放弃该事件。
Figure 1-12.响应链中的事件处理方法
系统为UIView触摸事件处理提供了四个方法
(1)- (void)touchesBegan:(NSSet<UITouch*> *)touches withEvent:(UIEvent*)event;
Tells this object that one or more new touches occurred in a view or window.
(2)- (void)touchesCancelled:(NSSet<UITouch*> *)touches withEvent:(UIEvent*)event;
Tells the responder when a system event (such as a system alert) cancels a touch sequence.
(3)- (void)touchesMoved:(NSSet<UITouch*> *)touches withEvent:(UIEvent*)event;
Tells the responder when one or more touches associated with an event changed.
(4)- (void)touchesEnded:(NSSet<UITouch*> *)touches withEvent:(UIEvent*)event;
Tells the responder when one or more fingers are raised from a view or window. 注意:如果是UIVIew的触摸事件需要自定义继承于UIView的子类,在子类中写这四个方法。如果是UIViewController的触摸事件直接在viewController中重写这四个方法就可以了。
三.寻找事件的firstResponder
1.具体步骤
点击屏幕,发生点击事件,UIKIt开始处理点击事件,事件传递方向UIApplication->keyWindow->viewController->rootView->view->subView,按照事件传递方向寻找最合适的响应者,firstResponder。下面详细介绍fUIView的irstResponder寻找过程。
(1)首先判断keyWindow是否能响应触摸事件或者说触摸事件是否在keyWindow范围内,如果不在则直接放弃后续查找
(2)UIKit通过遍历view hierarchy寻找the deepest subview作为firstResponder
下图是官方文档提供的解释
Figure 1-2(3)view hierarchy的遍历是采用倒叙的形式,从rootView的子控件开始遍历
例如:rootView包含三个视图,view1,view2,view3,其中view2又包含三个子视图subView1,subView2,subView3则遍历顺序是(本例子前提是所有view的- pointInside:withEvent:方法均返回YES,各个view的布局重叠)
rootView->view3->view2->subView3->subView2->subView1->view1
其中即使父控件符合响应者的要求,同样要遍历子控件寻找最合适的响应者。但是如果父控件不符合响应者要求(pointInside方法返回NO),则子控件不再遍历
2.依赖方法详解
(1)- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;下图是官方文档的解释
返回YES代表点击的point在当前遍历view的范围内
Figure 1-3(2)- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;下方图片是关于该方法的文档解释
Figure 1-4简要介绍一下,
(1)接收到点击事件,开始遍历视图,每个视图的hitTest方法都会调用pointInside:withEvent方法,该方法返回YES则继续执行hitTest方法
(2)通过override pointInside:withEvent方法让其return NO,则当前视图及其子视图放弃点击事件的处理,交给其父视图完成
(3)当透明度在0--0.01之间或者hidden属性被赋值YES时,这个方法不再调用
四.代码示例
UIView不能接受传递事件的三种情况
2.事件传递过程
3.用到的方法,使用方式
4.示例
(1)响应链论证
(2)修改响应链
5.Question and Summary
网友评论