【问题标题】:Combining a UILongPressGestureRecognizer with a UIPanGestureRecognizer将 UILongPressGestureRecognizer 与 UIPanGestureRecognizer 结合使用
【发布时间】:2011-03-30 08:43:48
【问题描述】:

我希望将 UILongPressGestureRecognizer 与 UIPanGestureRecognizer 结合使用。

UIPanGestureRecognizer 应该以长按开始。有没有一种简单的方法可以做到这一点?还是我真的必须编写自己的手势识别器?

我不想在主屏幕上显示类似内容。您按下一个图标,一段时间后图标开始摆动。之后,无需从屏幕上松开手指,我就可以开始拖动手指下的图标。

【问题讨论】:

    标签: objective-c cocoa-touch uigesturerecognizer uipangesturerecognizer uilongpressgesturerecogni


    【解决方案1】:

    实际上,您不必组合手势识别器 - 您可以仅使用 UILongPressGestureRecognizer 完成此操作...一旦您的触摸保持在“minimumPressDuration”的“allowableMovement”范围内,您就进入了 StateBegan。只要您不抬起任何手指,您就会保持持续的 longPressGesture - 因此您可以开始移动手指并通过 StateChanged 跟踪移动。

    长按手势是连续的。当允许的手指数量 (numberOfTouchesRequired) 在指定的时间 (minimumPressDuration) 内被按下并且触摸没有超出允许的移动范围 (allowableMovement) 时,手势开始 (UIGestureRecognizerStateBegan)。每当手指移动时,手势识别器就会转换到 Change 状态,并在任何手指抬起时结束 (UIGestureRecognizerStateEnded)。

    【讨论】:

    • 您可能会遇到很多问题。 UIPanGestureRecognizer 最好的地方之一是它可以让你平移整个窗口并仍然返回值,而 UILongPressGestureRecognizer 不会留下子视图(至少是带有 ClipsToBounds 的子视图)
    • 另外,当您移动 LongPress 时,没有velocity 可用
    【解决方案2】:

    我遇到了这个问题有点困难。接受的答案还不够。无论我在该方法中放入什么,都会调用 pan 或 longpress 处理程序。我找到的一个解决方案如下:

    1. 确保将手势识别器的委托分配给同一个类(在我的例子中是自己),并确保委托类是 UIGestureRecognizerDelegate
    2. 将以下委托方法添加到您的类(根据上面的答案):

      - (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
      shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 
           return YES;
      }
      
    3. 将以下委托方法添加到您的类中:

      - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
           if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && ! shouldAllowPan) {
                return NO;
           }
           return YES;
      }
      
    4. 然后添加一个属性或 ivar,它将跟踪是否应该允许开始平移(参见上面的方法)。在我的情况下BOOL shouldAllowPan

    5. 在您的initviewDidLoad 中将BOOL 设置为NO。在您的 longPress 处理程序中,将 BOOL 设置为 YES。我这样做:

      - (void) longPressHandler: (UILongPressGestureRecognizer *) gesture {
      
           if(UIGestureRecognizerStateBegan == gesture.state) {
              shouldAllowPan = NO;
           }
      
           if(UIGestureRecognizerStateChanged == gesture.state) {
              shouldAllowPan = YES;
           }
      }
      
    6. 在 panHandler 内部,我检查了 BOOL:

      - (void)panHandler:(UIPanGestureRecognizer *)sender{
          if(shouldAllowPan) {
                // do your stuff
          }
      
    7. 最后在 panHandler 中重置 BOOL:

      else if(sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateCancelled) {
          shouldAllowPan = NO;
      }
      
    8. 然后去喝杯啤酒祝贺自己。 ;)

    【讨论】:

    • +1。这些步骤确实帮助我解决了 op 的目标:长按后只允许拖动。仅 2 cmets:在步骤 5 中检查 Began 然后设置为 YES 就足够了。 ``` if(UIGestureRecognizerStateBegan == gesture.state) { self.shouldAllowDrag = YES; } ``` 在第 6 步中,没有必要检查 shouldAllowPan。 -- 对不起,未格式化的代码。
    • 我实施了 Andy 的解决方案,效果很好。为了获得我想要的响应能力,我还更改了最小长按持续时间: UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)]; lpgr.delegate = 自我; lpgr.minimumPressDuration = 0.05;
    • 这对我帮助很大。谢谢!我将添加一个 Swift 解决方案,以便它可以帮助其他人。
    • 很好的答案。谢谢!
    【解决方案3】:

    我找到了解决方案: 这个 UIGestureRecognizerDelegate 方法完全符合我的要求:

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
    shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    

    【讨论】:

      【解决方案4】:

      Andy B 在 Swift 中的方法,

      1. UIGestureRecognizerDelegate 委托添加到类

        class ViewController: UIViewController, UIGestureRecognizerDelegate
        
      2. 添加成员变量

        var shouldAllowPan: Bool = false
        
      3. 添加手势,需要将平移手势委托添加到VC。这是触发 shouldRecognizeSimultaneouslyWithGestureRecognizer 和 gestureRecognizerShouldBegin 函数所必需的

        // long press
        let longPressRec = UILongPressGestureRecognizer(target: self, action: "longPress:")
        yourView.addGestureRecognizer(longPressRec)
        
        // drag
        let panRec = UIPanGestureRecognizer(target: self, action: "draggedView:")
        panRec.delegate = self
        yourView.addGestureRecognizer(panRec)
        
      4. 允许同时使用手势

        func gestureRecognizer(UIGestureRecognizer,
        shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool {
            // println("shouldRecognizeSimultaneouslyWithGestureRecognizer");
            return true
        }
        
        func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
             // We only allow the (drag) gesture to continue if it is within a long press
             if((gestureRecognizer is UIPanGestureRecognizer) && (shouldAllowPan == false)) {
                 return false;
             }
             return true;
        }
        
      5. 在长按处理程序内部:

        func longPress(sender: UILongPressGestureRecognizer) {
        
            if(sender.state == .Began) {
                // handle the long press
            }
            else if(sender.state == .Changed){
                shouldAllowPan = true
        
            }
            else if (sender.state == .Ended) {
                shouldAllowPan = false
            }
        } 
        

      【讨论】:

      • 你忘了 6. 喝杯啤酒。 :) :)
      • @duyn9uyen 感谢您将其转换为 Swift。
      • @duyn9uyen 感谢您的转换,这就像一个魅力。
      • 太棒了!谢谢!要启用这两种手势(在我的项目中,没有使用 shouldAllowPan 的复杂性),我只需要添加UIGestureRecognizerDelegate,使UIPanGestureRecognizer 的delegate = self,并使用return true 添加gestureRecognizer(_: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith:UIGestureRecognizer) 函数跨度>
      • @RanLearns 同样在这里 ?
      【解决方案5】:

      为了组合更多的手势:

      1. 创建局部变量var shouldAllowSecondGesture : Bool = false
      2. 创建两个识别器

      let longPressRec = UILongPressGestureRecognizer(target: self, action: #selector(self.startDrag(sender:))) cell.addGestureRecognizer(longPressRec) let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(sender:))) cell.isUserInteractionEnabled = true cell.addGestureRecognizer(panGestureRecognizer)

      1. 扩展您的 VC 并实现 GestureRecognizerDelegate 以实现此方法。

        扩展 YourViewController : UIGestureRecognizerDelegate {

        func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
                return true
            }
        
        
        
        func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
                 // We only allow the (drag) gesture to continue if it is within a long press
                 if((gestureRecognizer is UIPanGestureRecognizer) && (shouldAllowPan == false)) {
                     return false
                 }
                 return true
            }
        
        
        @objc func startDrag(sender:UIPanGestureRecognizer) {
        
            if(sender.state == .began) {
                    // handle the long press
                }
            else if(sender.state == .changed){
                    shouldAllowPan = true
        
                }
                else if (sender.state == .ended) {
                    shouldAllowPan = false
                }
            }
        

      【讨论】:

        【解决方案6】:

        阅读 Apple 的 UIGestureRecognizer 类参考的“子类化注释”部分:

        https://developer.apple.com/library/prerelease/tvos/documentation/UIKit/Reference/UIGestureRecognizer_Class/

        【讨论】:

          【解决方案7】:

          我通过实现“动作:选择器?”的所需功能解决了这个问题。 “动作:选择器?”中 UIPanGestureRecognizer 的函数UILongPressGestureRecognizer 的函数。

          由于“UILongPressGestureRecognizer”没有成员“翻译”,我通过保存原始触摸的位置并从实际触摸位置中提取它来计算翻译。

          
          // in target class
          var initialTouchX : CGFloat
          var initialTouchX : CGFloat
          
          
          // in the @objc func for the UILongPressGestureRecognizer
          if sender.state == .began {
             initialTouchX = sender.location(in: sender.view).x
             initialTouchY = sender.location(in: sender.view).y
          }
          
          let translation = CGVector(dx: sender.location(in: sender.view).x - initialTouchX, dy: sender.location(in: sender.view).y - initialTouchY)
          
          
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-12-03
            • 1970-01-01
            • 2015-05-28
            相关资源
            最近更新 更多