【问题标题】:Touch events are delayed near left screen edge on iOS 9 only. How to fix it?触摸事件仅在 iOS 9 的左屏幕边缘附近延迟。如何解决?
【发布时间】:2015-11-09 22:34:02
【问题描述】:

我正在为 iOS 开发键盘扩展。在 iOS 9 上,除了键盘左边缘的按键外,按键会立即做出反应。那些反应大约有 0.2 秒的延迟。原因是触摸只是通过延迟传递给UIView,这是我键盘的根视图。在 iOS 8 上没有这样的延迟。

我的猜测是,这种延迟是由一些应该识别打开“正在运行的应用程序屏幕”手势的逻辑引起的。这很好,但键盘上的延迟是不可接受的。有什么办法可以毫不拖延地获得这些事件吗?也许只是在某些UIGestureRecognizer 上将delaysTouchesBegan 设置为false

【问题讨论】:

  • 您找到解决方案了吗?我们遇到了同样的问题。令人沮丧!
  • 我也想为此找到解决方案。
  • 还是没有解决办法?
  • @Rasto 我相信我已经提出了正确的解决方案。关心标记为已解决?)

标签: ios ios9 uigesturerecognizer uiresponder 3dtouch


【解决方案1】:

如果您有权访问viewwindow 属性,则可以访问这些系统手势识别器并将delaysTouchesBegan 设置为false

这是一个 swift 中的示例代码

if let window = view.window,
   let recognizers = window.gestureRecognizers {
   recognizers.forEach { r in
        // add condition here to only affect recognizers that you need to
        r.delaysTouchesBegan = false
   }
}

也相关:UISystemGateGestureRecognizer and delayed taps near bottom of screen

【讨论】:

    【解决方案2】:

    这适用于使用更高版本 iOS 的任何人(这适用于我的 iOS 9 和 10)。我的问题是由于滑动返回手势干扰了我的 touchesBegan 方法,阻止它在屏幕的最左边缘触发,直到触摸结束,或者系统识别出该移动不是滑动到返回手势。

    在控制器的 viewDidLoad 函数中,简单地说:

    self.navigationController?.interactivePopGestureRecognizer?.delaysTouchesBegan = false
    

    【讨论】:

      【解决方案3】:

      iOS11 以来的官方解决方案是覆盖您的UIInputViewControllerpreferredScreenEdgesDeferringSystemGestures

      https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys

      但是,它似乎至少不适用于 iOS 13。据我了解,这是因为preferredScreenEdgesDeferringSystemGesturesUIInputViewController 中被覆盖时无法正常工作,至少在iOS 13 上是这样。

      当您在常规视图控制器中覆盖此属性时,它会按预期工作:

      override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
          return [.left, .bottom, .right]
      }
      

      不过,UIInputViewController 并非如此。

      UPD:看来,手势识别器仍会毫无延迟地获得.began 状态更新。因此,您可以添加自定义手势识别器来处理触摸事件,而不是遵循下面相当混乱的解决方案。

      您可以将UILongPressGestureRecognizerminimumPressDuration = 0 快速添加到您的控制视图中进行测试。

      另一种解决方案:

      我最初的解决方法是在hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? 中调用touch down 效果,即使视图的触摸延迟也会调用。

      您必须忽略“真正的”触地事件,当它在大约 0.4 秒后触发或与 touch up inside 事件同时触发时。此外,最好仅在测试点位于约 20pt 横向边距内的情况下应用此 hack。

      例如,对于一个等于屏幕宽度的视图,实现可能如下所示:

      let edgeProtectedZoneWidth: CGFloat = 20
      
      override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
          let result = super.hitTest(point, with: event)
      
          guard result == self else {
              return result
          }
      
          if point.x < edgeProtectedZoneWidth || point.x > bounds.width-edgeProtectedZoneWidth
          {
              if !alreadyTriggeredFocus {
                  isHighlighted = true
              }
              triggerFocus()
          }
      
          return result
      }
      
      private var alreadyTriggeredFocus: Bool = false
      
      @objc override func triggerFocus() {
          guard !alreadyTriggeredFocus else { return }
          super.triggerFocus()
          alreadyTriggeredFocus = true
      }
      
      override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
          super.touchesCancelled(touches, with: event)
      
          alreadyTriggeredFocus = false
      }
      
      override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
          super.touchesEnded(touches, with: event)
      
          alreadyTriggeredFocus = false
      }
      

      ...其中triggerFocus() 是您在touch down 事件上调用的方法。或者,您可以覆盖touchesBegan(_:with:)

      【讨论】:

      • 完善您的 IOS 13 解决方案为我完成了这项工作(在 IOS 13 上)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-10
      相关资源
      最近更新 更多