iOS事件传递链与响应链

简介: iOS事件传递链与响应链

1、事件链


如下图所示,用户点击屏幕时,首先UIApplication对象先收到该点击事件,再依次传递给它上面的所有子view,直到传递到最上层,即UIApplication ——> UIWindow ——> RootViewController ——> View ——> Button,即传递链。

而反之Button ——> View ——> RootViewController ——> UIWindow ——> UIApplication则称为响应链。

简单总结,事件链包含传递链和响应链,事件通过传递链传递上去,通过响应链找到相应的UIResponse。



0f4f71a058954c6abdcde0f6ab62e5f4.png

2、传递链


由系统向离用户最近的view传递,如上图所示。具体流程如下:


1、用户在点击屏幕。

2、系统将点击事件加入到UIApplication管理的消息队列中。

3、UIApplication会从消息队列中取出该事件传递给UIWindow对象;

4、在UIWindow中调用方法hitTest:withEvent:返回最终相应的view;


1、在hitTest:withEvent:方法中调用pointInside:withEvent:来判断当前点击的点是否在UIWindow内部;

2、如若返回yes,则倒序遍历其子视图找到最终响应的子view;

3、如果最终返回一个view,那么即为最终响应view并结束事件传递,如果无值返回则将UIWindow作为响应者。见下图:

b36f18bd0204d7189e417539943cfb5.png

其中核心方法如下:


// recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;   
// default returns YES if point is in bounds
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;   


方法hitTest:withEvent:用来获取最终响应事件的view。

方法pointInside:withEvent:,用来判断点击的位置是否在视图范围内。

以下为UIView不接受事件处理的情况:


view.hidden = YES;
view.userInteractionEnabled = NO;
view.alpha < 0.01;

3、响应链


由离用户最近的view向系统传递。如下所示:

响应链处理具体流程:


1、若view的 viewcontroller 存在,则将该事件传递给其viewcontroller响应;如若不存在,则传递给其父视图;

2、若view的最顶层不能处理事件,则传递给UIWindow进行处理;

3、若UIWindow不能处理,则传递给UIApplication;

4、若UIApplication不能处理,则将该事件丢弃。


4、示例代码


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *touchView = self;
    // 1、判断 self 是否可以接受事件处理
    // 2、判断 self 是否在点击区间
    if (self.hidden == NO
        && self.alpha >= 0.01
        && [self pointInside:point withEvent:event]) {
        // 3、便利所有子view
        for (UIView *subView in self.subviews) {
            // 4、获取点击的点在子view上的坐标
            CGPoint subPoint = [subView convertPoint:point fromView:self];
            // 5、递归获取点击响应的子view
            UIView *subTouchView = [subView hitTest:subPoint withEvent:event];
            if (subTouchView) {
                touchView = subTouchView;
                break;;
            }
        }
    } else {
        // 不接受事件处理直接返回 nil;
        touchView = nil;
    }
    return touchView;
}


优秀讲解推荐: https://blog.csdn.net/songzhuo1991/article/details/122667980



相关文章
|
开发框架 JavaScript 前端开发
理解iOS端的WebView同层组件
同层组件的目标是将原生组件渲染在与其他Web组件同一层级中。在iOS中,我们使用WKWebView来创建Web视图,WKWebView在进行解析渲染时,会将Web组件渲染到WKCompositingView上,这个View是一个原生的UIView子类,通常WKWebView内核会将多个组件共同渲染到同一个WKCompositingView上,但是如果某个HTML标签的style设置了overflow: scroll属性,并且内容超出容器的大小,WKWebView就会为其单独的创建一个WKChildScrollView,因此如果我们可以找到这个View,并和对应的Web组件一一关联起来,就可以将
1341 0
IOS_ViewController生命周期内各个函数的调用次序
IOS_ViewController生命周期内各个函数的调用次序
60 0
|
存储 安全 API
iOS AutoReleasePool 自动释放池以及RunLoop分析(下)
1.runloop是什么? 2.runloop和线程的关系? 3.runloop是什么时候创建的?
762 0
|
存储 对象存储 iOS开发
iOS AutoReleasePool 自动释放池以及RunLoop分析(上)
自动释放池 -> 内存自动回收机制 -> 变量release的时机延迟 对象 -> 正常情况下,变量会在超出其作用域的时立即release -> 加入到了自动释放池中 -> 不会立即释放,会等到runloop休眠/超出autoreleasepool作用域{}之后才会被释放
357 0
|
设计模式 前端开发 iOS开发
iOS对UIViewController生命周期和属性方法的解析(一)
iOS对UIViewController生命周期和属性方法的解析
242 0
iOS对UIViewController生命周期和属性方法的解析(一)
|
iOS开发
iOS对UIViewController生命周期和属性方法的解析(二)
iOS对UIViewController生命周期和属性方法的解析
218 0
iOS对UIViewController生命周期和属性方法的解析(二)
|
安全 iOS开发 开发者
iOS中RunLoop机制浅探
iOS中RunLoop机制浅探
143 0
|
Android开发 Java
Android触摸事件(上)——事件的由来
从接触Android开发以来,貌似Android的事件就一直伴随着我。从一开始的setOnclickListener到后来的setOnTouchListener以及各种手势的事件,关于Android的事件传递机制,我觉得很多人都看了不止一遍了。
1011 0
|
iOS开发
ios 事件链 和 响应链 初步理解
当我们在手机屏幕上进行了一次点击,或者滑动,轻扫手机屏幕,接下来,我们的手机该如何回应我们的指令,软件又经历了哪些过程呢?这篇文章是我自己的简单理解,如有不当,请指出。
916 0