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组件一一关联起来,就可以将
1311 0
|
缓存 JavaScript 前端开发
iOS 自动适配的 WebView 封装 (上)
iOS 自动适配的 WebView 封装 (上)
844 0
iOS 自动适配的 WebView 封装 (上)
|
JavaScript 前端开发 Android开发
iOS 自动适配的 WebView 封装 (下)
iOS 自动适配的 WebView 封装 (下)
191 0
iOS 自动适配的 WebView 封装 (下)
|
安全 iOS开发 开发者
iOS中RunLoop机制浅探
iOS中RunLoop机制浅探
133 0
在使用蓝牙接口,遇到IOS下正常,Android下不正常的简易处理方法
如果遇到以上的情况怎么办,先确定下在调试的时候是否打开了调试面板, 如果有打开请关闭调试面板看是否还有问题,目前在安卓上打开调试面板是会有影响到蓝牙接口的使用,从之前遇到过这些问题的统计中也确实是因为这个原因
450 0