为双指手势创建自定义的UIGestureRecognizer

8

我有一个自定义的UIGestureRecognizer用于双指手势,它完美地工作,只是很挑剔同时触摸iOS设备以使touchesBegan调用2个触摸。即使我尝试使用两个手指,touchesBegan经常只被一个Touch调用。

有没有办法使对触摸数量的识别更具容忍性,以便您可以更灵活地在触摸屏幕上放置手指?

我注意到,即使您首先放下一个手指,然后再过一段时间放下另一个手指,但仍然保持第一个手指按下,双指轻敲也会被识别。

这是我的touchesBegan函数的代码:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {

      if touches.count != 2 {
         state = .failed
         return
      }

      // Capture the first touch and store some information about it.
      if trackedTouch == nil {
         trackedTouch = touches.min { $0.location(in: self.view?.window).x < $1.location(in: self.view?.window).x }
         strokePhase = .topSwipeStarted
         topSwipeStartPoint = (trackedTouch?.location(in: view?.window))!
         // Ignore the other touch that had a larger x-value
         for touch in touches {
            if touch != trackedTouch {
               ignore(touch, for: event)
            }
         }
      }
   }

1
你的代码写着 if touches.count != 2 { state = .failed }。这与你说的完全相反。你说你不希望仅仅因为计数不为2就立刻失败,所以不要这样做! - matt
但是我只想识别两个手指的手势!?什么时候我才能确定手势不是使用两个手指并且应该失败呢?我可能在这里误解了什么... - Melodius
我应该在哪里检查手势是否使用了两个手指?touchesBegan只会被调用一次吗?还是? - Melodius
你能发布你的手势初始化代码吗? - Adrian
我曾使用过各种手势识别器,但从未遇到过这个问题。如果不知道您要实现什么,您可能最好使用其中一个子类UIPanGestureRecogniser或UISwipeGestureRecongiser,它们可以指定最小和最大触摸数。对我来说,这些一直都很可靠。 - Dale
显示剩余3条评论
5个回答

2
对于双指手势,touchesBegan 很可能会被调用两次:一次是当您将第一个手指放在屏幕上时,另一次是当您放置第二个手指时。
在保持的状态下,您应该跟踪所有触摸(或者说,所有当前触摸),只有在接收到两个触摸并且手势的开始条件已满足时才开始手势。
public class TwoFingerGestureRecognizer: UIGestureRecognizer {
    private var trackedTouches: Set<UITouch> = []

    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        for touch in touches {
            if self.trackedTouches.count < 2 {
                self.trackedTouches.insert(touch)
            }
            else {
                self.ignore(touch, for: event)
            }
        }

        if self.trackedTouches.count == 2 {
            // put your current logic here
        }
    }

    public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
    }

    public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        self.trackedTouches.subtract(touches)
    }

    public override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
        self.trackedTouches.subtract(touches)
    }

    public override func reset() {
        super.reset()

        self.trackedTouches = []
    }
}

1
不要担心 touchesBegan:withEvent:,而是使用touchesEnded:withEvent:touchesMoved:withEvent:。如果结束状态不包含两个手指,则将其设置为.failed,否则将其设置为.ended。同时轻敲屏幕无法同时使用多个手指,因此在touchesMoved:withEvent:中会发现两个手指。我不确定touchesEnded:withEvent:是否有效,因为同时移除两个手指和同时应用两个手指一样困难,但值得尝试以查看其反应。

1
我建议你让代码更加容错。虽然touchesBegan/Moved/Ended/Cancelled响应“一个或多个触摸”的事件(如苹果文档所述),但依赖用户同时用2个手指精确触摸屏幕并不理想。这是假设你启用了多点触控的情况下。尝试自己跟踪触摸并在收集到2个触摸时执行逻辑。显然,当你的触摸数量变得更少或更多时,你也必须跟踪并相应地处理事情,但如果你的手势只针对2个手指(除了你必须在touchesBegan中添加的额外逻辑),我猜你已经在处理了。

0

不确定为什么其他人使用touchesMoved:withEvent来回答你的问题,但也许你需要一个github示例。

双指移动示例。


-1

你是否考虑使用touchesMoved来实现所需的结果?此外,你可以在将状态设置为失败之前实现一个计数器。别忘了设置isMultipleTouchEnabled = true

  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if touches.count != 2 {
        print("we do NOT have two touches")
        if counter > 100   { // 100 "more fogiven"
            state = .failed
        }
        counter += 1
        return
    } else {
        print("we have to two touches")
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接