美文网首页我爱编程
事件响应链的一个bug

事件响应链的一个bug

作者: 桔子听 | 来源:发表于2018-04-16 14:36 被阅读13次

源于同事遇到的一个问题,简化情况:

storyboard

红色的View是加在ViewController上的一个自定义View
代码如下:

import UIKit

class RedView: UIView {

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("red touchesBegan")
        self.next?.touchesBegan(touches, with: event)
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("red touchesMoved")
        self.next?.touchesMoved(touches, with: event)
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("red touchesEnded")
        self.next?.touchesEnded(touches, with: event)
    }
}

事件响应的原理是,如果这个View没有处理这个事件(即没有实现touchesXXX等方法),那么这个事件直接传递给superView处理,这里的superView当然就是ViewController里面的View,如果这个View没有处理,那么交给所属的ViewController处理。具体的事件响应链这里不做讨论。

那么这里的情况是,RedView做了事件处理,并且在处理之后,又原封不动的把事件抛给事件响应链里的下一个接收者。这里的self.next就是获取下一个事件接收者。

ViewController代码:

import UIKit

class ViewController: UIViewController {

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("vc touchesBegan")
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("vc touchesMoved")
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("vc touchesEnded")
    }

}

我点击red View会有什么打印?
的确如预期的那样。

点击输出

如果我想触发touchesMoved,也就是在red View滑动,会是什么结果?

滑动输出

只有red view会持续接收到touchesMoved事件。vc接收到一次就终止了,就连最后的touchesEnded事件也没有接收到。

这种情况只会发生在ViewController里的View上。也就是如果是两个自定义view的话,不会有这个问题?

那么究竟是什么问题?从事件响应链上来说,并没有什么特殊的地方,难道是ViewController里的View有什么特殊处理吗?

通过下面stackoverflow讨论的结果是:

Passing touchesMoved events to superview only passes first event

IOS 5: UIScrollView not pass touches to nextResponder

self.nextResponder vs super for touchesMoved

touchesMoved not firing in iOS5 for the iPhone for UIScrollView

  • 1.iOS5之后出现这个问题,iOS之前是正常的。

  • 2.官方已经给出答复,这个是iOS的bug。

  • 3.只能用其他方式替代。

最直接的解决方法是,将上面的red View代码改为

import UIKit

class RedView: UIView {

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("red touchesBegan")
        self.next?.next?.touchesBegan(touches, with: event)
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("red touchesMoved")
        self.next?.next?.touchesMoved(touches, with: event)
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("red touchesEnded")
        self.next?.next?.touchesEnded(touches, with: event)
    }
}

self.next?改为self.next?.next?,意思是,将事件传递到下下个事件接收者,也就是ViewController,而不再是ViewController里的View。我们可以得到想要的结果:

解决方法

相关文章

  • 事件响应链的一个bug

    源于同事遇到的一个问题,简化情况: 红色的View是加在ViewController上的一个自定义View:代码如...

  • iOS 响应链

    iOS开发 - 事件传递响应链iOS 响应者链,事件的传递事件传递之响应链Cocoa Touch事件处理流程--响...

  • UIControl && UIGestureRecognizer

    事件传递和响应链 一. 事件传递 二.响应链 响应链: 三.UIGestureRecognizer 四.cance...

  • IOS开发 事件响应链

    本节学习内容: 1.事件响应链的概念 2.事件响应链的传递机制 3.事件响应链的应用 响应顺序 Subview>M...

  • 深入浅出iOS事件机制

    深入浅出iOS事件机制事件传递:响应链事件传递响应链

  • 响应链和事件分发

    什么是响应链和事件分发: 响应链:由响应者对象构成链状结构,能够响应点击、拖拽等事件 事件分发:屏幕捕捉到触摸事件...

  • iOS知识收集

    1. 响应者链 1.1 Cocoa Touch事件处理流程--响应者链 1.2 事件传递之响应链 多线程 http...

  • 转载:响应者链工作原理

    响应者链 响应者链是由一个一个响应者组成的长链;响应者链定义了iOS中触摸事件的交互规则;如果hit-test检测...

  • ios响应者链

    iOS 响应者链 字数418 阅读41 评论0 喜欢3 响应者链 响应者链是一个响应者的连接序列,事件或者动作消息...

  • iOS响应链

    响应链: 当事件发生的时候,响应链首先被发送给第一个响应者(往往是事件发生的视图,也就是用户触摸屏幕的地方)。事件...

网友评论

    本文标题:事件响应链的一个bug

    本文链接:https://www.haomeiwen.com/subject/vwqekftx.html