【问题标题】:iOS 14 UISlider ignoring additional GestureRecognizer (PanGesture, LongTapGesture, TapGesture)iOS 14 UISlider 忽略额外的 GestureRecognizer(PanGesture、LongTapGesture、TapGesture)
【发布时间】:2020-08-07 16:17:40
【问题描述】:

我有一个视图控制器,用户可以在其中移动 UIButton、UISlider 和一个基于 UIView 的自定义控件,方法是在屏幕上平移控件。此视图控制器用于创建用户自定义的控件布局。这一切都是通过将 PanGestureRecognizer 添加到 UIControl 以移动控件相对于用户手指位置的位置来完成的。

let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(pan))
panRecognizer.delegate = self;
myslider.addGestureRecognizer(panRecognizer)

~~~~~~~~~~~~
//pan handler method

@objc func pan(_ gestureRecognizer: UIPanGestureRecognizer) {
        let translation = gestureRecognizer.translation(in: view)
        
        guard let gestureView = gestureRecognizer.view else {
            return
        }
        //Move the center to user's finger location
        gestureView.center = CGPoint(x: gestureView.center.x + translation.x, y: gestureView.center.y + translation.y);
        gestureRecognizer.setTranslation(.zero, in: view);

        if (gestureRecognizer.state == .ended) {
           //Save the new location inside data. Not relevant here.
        }
}

对于我上面提到的所有控件,这在 iOS 13 及更低版本中运行良好(UISlider 有点小故障,但它仍然响应平移手势,我不需要 uislider 的值,所以它是安全的忽视)。然而,在 iOS 14 中测试应用程序显示 UISlider 完全忽略了 PanGesture(通过添加从未在平移手势处理方法中调用的断点来证明)。 我查看了苹果关于 UISlider 的文档,发现与手势处理没有任何变化,所以这必须在更深层次的杠杆中刻意完成。我的问题是:有什么方法可以“强制”执行我的自定义手势而不是 UISlider 的手势,而无需创建透明按钮覆盖(我不知道这是否有效)/为此创建虚拟滑块?

此外,我还向控件添加了 UILongPressGestureRecognizer 和 UITapGestureRecognizer。这在其他 UIButton 上运行良好,但在 iOS14 中被 UISlider 完全忽略(在 iOS 13 中一切正常)。

谢谢。

【问题讨论】:

  • 我在 iOS 14 模拟器上测试过。我只需要使 VC 类符合 UIGestureRecognizerDelegate。效果很好,我可以在视图中移动滑块。你在哪里创建 panRecognizer ?在 viewDidLoad 中?您是否在 pan(_gestureRecognizer: UIPanGestureRecognizer) 的开头插入了一条打印语句来检查它是否被调用?你没有在滑块上设置约束以防止移动吗?
  • 也使用 XCode 12ß4 进行了测试。完美运行。所以,我再次问:你在哪里创建 panRecognizer ?
  • 好吧..所以我只是再挖一些,我找到了问题的根源。我创建了一个新项目,和上面一样,它按预期工作,就像你说的那样。问题出在 beginTracking 方法上。我的这个 UISlider 被子类化为一个自定义类,覆盖了始终返回 true 的 beginTracking 方法。在 iOS 13 中,此方法不会“覆盖”gestureRecognizer。但是,在 iOS 14 中,行为发生了变化,导致了我的问题。
  • 太好了,你找到了原因。但是,下次请正确描述情况。你从来没有说过你是 UISlider 的子类,没人能猜到。

标签: ios swift uigesturerecognizer uislider


【解决方案1】:

好的.. 经过更多挖掘并从“claude31”那里获得关于制作新的干净项目并从那里进行测试的提示后,我自己找到了答案。

问题出在覆盖的 beginTracking 函数上。我的这个 UISlider 实际上被子类化为一个自定义类,并在其中重写了 beginTracking 函数,如下面的代码:

override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
    let percent = Float(touch.location(in: self).x / bounds.size.width)
    let delta = percent * (maximumValue - minimumValue)

    let newValue = minimumValue + delta
    self.setValue(newValue, animated: false)
    super.sendActions(for: UIControl.Event.valueChanged)
    return true

}

如果触摸在 UISlider 的边界内,这会使滑块立即移动到用户手指的位置(无需先触摸 thumbTrack 并将其滑动到用户想要的位置)。

在 iOS 13 中,此功能不会阻止手势识别器被识别。然而,在 iOS 14B4 中,重写此函数,在其中使用 sendActions(for:) 方法会导致添加的手势识别器被完全忽略,无论是平移手势、长按手势,甚至是点击手势。

对我来说,解决方案是简单地添加一个状态来检查此视图控制器中是否需要平移手势。因为,幸运的是,我只需要在不需要自定义 beginTouch 功能的视图控制器中添加手势识别器,反之亦然。


编辑: 最初我写道,问题的原因是由于总是返回真值,但是,我只是重新阅读了文档,这个函数的默认返回值也是真值。所以我认为这个问题的根本原因是 sendActions(for:) 方法,导致添加的gestureRecognizer被忽略。我上面的答案已被编辑以反映这一点。

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 2013-06-10
    • 2021-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多