同一 UIView 中的两个 UIPanGestureRecognizer 同时调用

Two UIPanGestureRecognizers in the same UIView Invoked Simultaneously

提问人:Gizmodo 提问时间:9/17/2023 最后编辑:Gizmodo 更新时间:9/18/2023 访问量:39

问:

我希望两个同时工作。在中心上方滑动时,将调用 panGesture1,在中心下方滑动将调用 panGesture2。必须同时使用这两种方法。UIPanGestureRecognizersUIView

let panGesture1 = UIPanGestureRecognizer()
let panGesture2 = UIPanGestureRecognizer()

self.panGesture1.addTarget(self, action: #selector(self.panGesture1Detected(_:)))
self.panGesture1.delegate = self
self.panGesture1.minimumNumberOfTouches = 1
self.panGesture1.maximumNumberOfTouches = 1
self.panGesture1.cancelsTouchesInView = false
self.panGesture1.delaysTouchesBegan = false
self.panGesture1.delaysTouchesEnded = true
self.panGesture1.requiresExclusiveTouchType = false
self.view.addGestureRecognizer(self.panGesture1)

self.panGesture2.addTarget(self, action: #selector(self.panGesture2Detected(_:)))
self.panGesture2.delegate = self
self.panGesture2.minimumNumberOfTouches = 1
self.panGesture2.maximumNumberOfTouches = 1
self.panGesture2.cancelsTouchesInView = false
self.panGesture2.delaysTouchesBegan = false
self.panGesture2.delaysTouchesEnded = true
self.panGesture2.requiresExclusiveTouchType = false
self.view.addGestureRecognizer(self.panGesture2)



func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
   return true
}


func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == self.panGesture1 {
            if gestureRecognizer.location(in: self.view).y < self.view.bounds.midY {
                //Pangesture 1 is above the first half of view. So good.
                return true
            } else {
                return false
            }
        }

        else if gestureRecognizer == self.panGesture2 {
            if gestureRecognizer.location(in: self.view).y > self.view.bounds.midY {
                //Pangesture 2 is below the first half of view. So good.
                return true
            } else {
                return false
            }
        }
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {

        return true
}

本期

当第一次触摸平移时,它会识别出相应的平移手势。当第二次触摸下来时,它假定这是针对当前活动的平移手势。因此,基本上不可能同时激活两个平移手势。

轻松出路

在屏幕的一半上放置一个虚拟的 UIView,并在那里激活其中一个平移手势?

这甚至可能吗?

在同一视图中使用两个平移手势是否可能?

iOS Swift UIVieview UIPANGogestureRecognizer

评论

1赞 HangarRash 9/17/2023
您遗漏了一些非常重要的信息 - 如何使用这两个平移手势?为什么将两个视图合二为一?可以只使用一个,还是必须同时平移两个功能才能使某些功能正常工作?请编辑您的问题,并提供有关您实际想要实现的目标的更多详细信息。
0赞 Gizmodo 9/18/2023
PanGesture1 用于视图的上半部分,其他用于视图的下半部分。这是在iPad上用双手使用。
1赞 EmilioPelaez 9/18/2023
如果你想跟踪两根手指独立移动,你可能需要比手势更灵活的东西,毕竟拖动两个不同的手指并不是真正的手势。我建议考虑创建自己的识别器,或者将 UIView 子类化并重写触摸方法。
0赞 Gizmodo 9/19/2023
是的,看起来最好的方法是将两个虚拟视图垂直堆叠,并将每个平移手势附加到相应的虚拟视图。这样,就可以同时操作。

答:

1赞 Matic Oblak 9/18/2023 #1

我确实希望您得到一个使用 2 个手势识别器的答案。我自己玩过,但放弃了。

在您的视图上启用可能仍有可能,但我没有设法让它工作。isMultipleTouchEnabled

无论如何,平移手势是最容易自己实现的。他们绝对没有微调。您只需要跟踪拖拽。下面是一个使用触摸事件的非常简单的实现:

class CustomDragRecogniser {

    private var currentTouch: UITouch?

    // Control:
    var mayBegin: (_ touch: UITouch) -> Bool = { _ in true }
    var onBegin: (_ touch: UITouch) -> Void = { _ in }
    var onDrag: (_ touch: UITouch) -> Void = { _ in }
    var onEnded: (_ touch: UITouch) -> Void = { _ in }

    // Input:
    func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard currentTouch == nil else { return } // Already in progress
        if let matching = touches.first(where: { mayBegin($0) }) {
            currentTouch = matching
            onBegin(matching)
        }
    }

    func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let matching = touches.first(where: { $0 === currentTouch }) {
            onDrag(matching)
        }
    }

    func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let matching = touches.first(where: { $0 === currentTouch }) {
            currentTouch = nil
            onEnded(matching)
        }
    }

    func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let matching = touches.first(where: { $0 === currentTouch }) {
            currentTouch = nil
            onEnded(matching)
        }
    }

}

class SimultaneousGesturesViewController: UIViewController {

    private var recognisers: [CustomDragRecogniser] = []


    override func viewDidLoad() {
        super.viewDidLoad()

        view.isMultipleTouchEnabled = true

        let topRecogniser = CustomDragRecogniser()
        topRecogniser.mayBegin = { [weak self] touch in
            guard let view = self?.view else { return false }
            return touch.location(in: view).y < view.bounds.height*0.5
        }
        topRecogniser.onDrag = { [weak self] touch in
            guard let view = self?.view else { return }
            print("G1 moved to \(touch.location(in: view))")
        }

        let bottomRecogniser = CustomDragRecogniser()
        bottomRecogniser.mayBegin = { [weak self] touch in
            guard let view = self?.view else { return false }
            return touch.location(in: view).y >= view.bounds.height*0.5
        }
        bottomRecogniser.onDrag = { [weak self] touch in
            guard let view = self?.view else { return }
            print("G2 moved to \(touch.location(in: view))")
        }

        recognisers = [topRecogniser, bottomRecogniser]
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        recognisers.forEach { $0.touchesBegan(touches, with: event) }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        recognisers.forEach { $0.touchesMoved(touches, with: event) }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        recognisers.forEach { $0.touchesEnded(touches, with: event) }
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        recognisers.forEach { $0.touchesCancelled(touches, with: event) }
    }

}

您应该能够将其打包到视图或其他工具中,以屏蔽大部分代码或代码以实现可重用性。

评论

0赞 HangarRash 9/18/2023
为什么不子类?UIGestureRecognizer
0赞 Matic Oblak 9/18/2023
@HangarRash我只是没有尝试过。我很有可能会遇到与使用当前 UIPanGestureRecognizeniser 相同的问题。但是,如果不是,如果重新发明 UIPanGestureRecogniser 可以解决问题,那么我同意这是一种更好的方法。
2赞 HangarRash 9/18/2023
在我尝试提供解决方案之前,我正在等待 OP 用相关细节更新他们的问题。该问题目前是一个 XY 问题。
0赞 Gizmodo 9/18/2023
我修复了代码中的错误。