如何限制 LongPressGesture-began 和 LongPressGesture-ended 之间的进程

How to limit a process between LongPressGesture-began and LongPressGesture-ended

要求很简单:我想在用户触摸屏幕并按住手指时启动 activity(例如在屏幕上画圆圈)。此activity 再次抬起手指时应立即停止。所以我用了UILongPressGestureRecognizer。这会产生一个 .began 和 .ended 事件。但问题是,当基于 .began 事件启动 activity 时,只要 activity 正在进行,.ended 事件就不会发生。我对 .ended 事件的意图是它应该停止启动 activity。这样,activity 执行将被限制在手指触碰和抬起之间的时间。

我将我的示例代码增强为甚至 2 个独立的 UILongPressGestureRecognizers,它们可以使用 UIGestureRecognizerDelegate 构造同时工作。两个识别器的同步功能起作用。但是,当其中一个启动 activity 时,第二个识别器在 activity 结束之前也不会接收事件。

如何实现这个微不足道的要求?

这是我的示例代码。 activity 被简化为 10 个打印语句。每秒 1 个。当触摸手指在 2 秒后抬起时,将继续循环剩余的 8 秒。

import UIKit

class ViewController: UIViewController {
    var fingerDown = false

    @IBOutlet var MyLongPress1: UILongPressGestureRecognizer!

    @IBOutlet var MyLongPress2: UILongPressGestureRecognizer!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func handleLongPress1(_ gesture: UILongPressGestureRecognizer) {
    
        if (gesture as AnyObject).state == .began {
            print("longPress1 began")
            fingerDown = true
            myActivity()
        } else  if (gesture as AnyObject).state == .ended {
            print("longPress1 ended")
            fingerDown = false
        }
    }

    @IBAction func handleLongPress2(_ gesture: UILongPressGestureRecognizer) {
    
        if (gesture as AnyObject).state == .began {
            print("longPress2 began")
            fingerDown = true
        } else  if (gesture as AnyObject).state == .ended {
            print("longPress2 ended")
            fingerDown = false
        }
    }

    func myActivity() {
        var count = 0
        while fingerDown && count < 10 {
            sleep(1)
            count += 1
            print("in myActivity \(count)")
        }
    }
}

extension ViewController: UIGestureRecognizerDelegate {

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

如有任何好的建议,我们将不胜感激!

您正在函数中执行同步代码。

相反,您应该做的是创建一个异步的、可取消的操作,它从 .began 事件开始,并在 .ended 事件上取消它。用于此的代码太复杂而无法编写并放在此处作为答案。您可以参考并发/异步代码教程 like this one 来正确实现您正在尝试做的事情。


一个更简单但更脏但仍然有效的解决方案是简单地异步调用您的函数,因此它不会阻塞主线程:

    DispatchQueue.global().async {
        self.myActivity()
    }

在您的代码中进行这样的异步调用是可以的,但是代码中存在其他问题,导致它不是很干净。 例如您的代码取决于额外的 fingerDown 状态,而不是实际的手势状态;使用 sleep 等..