欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS-事件传递和响应机制

程序员文章站 2024-03-20 13:26:04
...
NSLog(@"SHOW TIME...");

App通过响应者对象来接收和处理事件,响应者对象都是UIResponder的子类对象,常见的UIView,UIVieController、UIWindow和UIApplication都是UIResponder的子类。

一、事件传递流程

- 当点击屏幕后,事件会传递给UIApplication,在由UIApplication传递给当前的UIWindow;

- UIWindow通过调用- (UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event方法返回响应视图。

- 其中hitTest:withEvent:内部会调用- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event方法判断点击位置是否在UIWindow范围内,

- 如果是的话就会【倒序遍历】(最后添加的视图最先遍历)UIWindow的子视图,从而找出响应视图并返回。

流程如下图1-1
iOS-事件传递和响应机制

                                                                                       图1-1 事件传递流程

二、hitTest:withEvent:内部都做了什么?

1、 首先会判断当前视图是否有响应事件的能力,当视图隐藏属性hidden=NO、交互userInteractionEnabled=YES、透明度alpha>0.01三者同时满足才拥有响应能力。
2、 若当前视图未拥有响应能力,hitTest方法直接返回nil,并且将当前视图的父视图作为时间响应者返回。
3、 若当前视图拥有响应事件能力,则继续判断事件点击位置是否在当前视图范围内,若不在则输出效果同步骤2,若在范围内,则倒序遍历当前视图的子视图,重复以上动作,直到找出响应视图。

具体流程如图1-2

iOS-事件传递和响应机制

                                                                 图1-2 hitTest:withEvent:内部实现流程

三、事件的响应链机制流程

当事件触发后,系统会自动为我们找到合适的响应对象,响应对象对事件逐级向上响应的过程就是响应链,和事件传递流程可以说是恰好相反,如下图1-3

iOS-事件传递和响应机制

                                                                                                    图1-3 事件响应链流程

- 我们根据下图1-4来走一遍响应机制。

iOS-事件传递和响应机制

                        图1-4 事件响应流程示例图

如图1-4,View A视图有View B2视图,View B2视图内有View C1和View C2两个子视图,此时点击空白圆的位置,系统会找到响应者C2视图,若C2视图不处理这个响应事件,会把事件传递给下一个响应者B2,若B2也不处理,在把事件传递给下一个响应者A视图,如果依旧不处理,则会沿着响应链向上传递直到传递给UIApplicationDelegate。如果一直没有视图响应事件的话,系统就会忽略这个事件(不会产生crash)。

四、Responder提供4个事件处理方法

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;

- 其中touches是一个存放UITouch对象的集合,UITouch对象保存着手指触摸相关信息,如触摸位置、时间等。

- 一根手指触摸,会调用一次touchesBegan:方法,并且touches集合中包含1个UITouch对象;

- 两根手指同时触摸一个view,view只调用一次touchesBegan:方法,并且touches集合中包含2个UITouch对象;

- 两根手指一前一后触摸一个view,view调用两次touchesBegan:方法,并且每次touches都只包含1个UITouch对象;

 

NSLog(@"END...");