将长按手势和拖动手势结合在一起

Posted

技术标签:

【中文标题】将长按手势和拖动手势结合在一起【英文标题】:Combine longpress gesture and drag gesture together 【发布时间】:2012-02-14 05:50:51 【问题描述】:

我正在移动我的观点

UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveRight:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[bubbleView[rightCnt] addGestureRecognizer:panRecognizer];
[panRecognizer release];

现在,我想通过长按拖动来做同样的事情。

有什么想法吗?

【问题讨论】:

【参考方案1】:

UILongPressGestureRecognizer 已经为你做了你想做的事。查看UIGestureRecognizerState 属性。来自documentation:

长按手势是连续的。手势开始 (UIGestureRecognizerStateBegan) 当允许的手指数 (numberOfTouchesRequired) 已按指定时间段 (minimumPressDuration) 并且触摸不会超出 允许的移动范围(allowableMovement)。手势 每当手指移动时,识别器都会转换到 Change 状态, 并且它在任何手指时结束(UIGestureRecognizerStateEnded) 被提升了。

所以基本上在你的UILongPressGestureRecognizerselector 被调用之后你会听 UIGestureRecognizerStateBegan、UIGestureRecognizerStateChanged、UIGestureRecognizerStateEnded。在UIGestureRecognizerStateChanged 期间不断更改您的视图框架。

- (void)moveRight:(UILongPressGestureRecognizer *)gesture

    if(gesture.state == UIGestureRecognizerStateBegan)
    
        //if needed do some initial setup or init of views here
    
    else if(gesture.state == UIGestureRecognizerStateChanged)
    
        //move your views here.
        [yourView setFrame:];
    
    else if(gesture.state == UIGestureRecognizerStateEnded)
    
        //else do cleanup
    

【讨论】:

我正在使用 CGPoint translatePoint = [(UILongPressGestureRecognizer*)sender translationInView:self.view];但是要长按我必须使用什么? 试试[yourView setFrame:CGRectMake(xCoord,yCoord,height,width)] 但是我怎样才能得到translationPoint 为什么需要translatedPoint?您想长按视图并拖动它吗?在UIGestureRecognizerStateEnded 中,您编写代码来获取该视图的新位置。 @SrikarAppal 你没有完全回答这个问题。 PJR 想知道每次调用UIGestureRecognizerStateChanged 时如何获取手指坐标。答案是:使用[myGestureRecognizer locationInView:aView]【参考方案2】:
@implementation MyViewController 
    CGPoint _priorPoint;


- (void)moveRight:(UILongPressGestureRecognizer *)sender 
    UIView *view = sender.view;
    CGPoint point = [sender locationInView:view.superview];
    if (sender.state == UIGestureRecognizerStateChanged) 
        CGPoint center = view.center;
        center.x += point.x - _priorPoint.x;
        center.y += point.y - _priorPoint.y;
        view.center = center;
    
    _priorPoint = point;

【讨论】:

你最初将priorPoint设置为什么? 你不需要特别设置它,因为sender.stateChanged之前总是Began。这意味着_priorPoint 在使用之前总是会被初始化。 但是priorPoint 最初是从(0.0, 0.0) 开始的,所以使用这个代码,初始触摸会使对象的中心移动超过点位置和中心位置的差值。我必须在Began 状态下将priorPoint 设置为视图的中心 对于未来的读者 - 我希望将 UIPanGestureRecognizer 的拖动运动与使用 UITapGestureRecognizer 对初始点击采取行动的能力相结合。我在这里玩了 UILongPressGestureRecognizer 的答案,但是虽然这似乎对其他人有用,但是在移动对象时计算对象的位置并没有达到使用 UIPanGestureRecognizer 的质量——这就是我最终返回使用的质量。对我来说,this answer 有助于提供一种同时识别手势识别器的解决方案【参考方案3】:

在 Swift 中,这可以使用下面的代码来实现

class DragView: UIView  
  // Starting center position
  var initialCenter: CGPoint?

  override func didMoveToWindow() 
    super.didMoveToWindow()
    // Add longPress gesture recognizer
    let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(gesture:)))
    addGestureRecognizer(longPress)
  

  // Handle longPress action
  func longPressAction(gesture: UILongPressGestureRecognizer) 
    if gesture.state == .began 
        guard let view = gesture.view else 
            return
        
        initialCenter = gesture.location(in: view.superview)
    
    else if gesture.state == .changed 
        guard let originalCenter = initialCenter else 
            return
        

        guard let view = gesture.view else 
            return
        

        let point = gesture.location(in: view.superview)

        // Calculate new center position
        var newCenter = view.center;
        newCenter.x += point.x - originalCenter.x;
        newCenter.y += point.y - originalCenter.y;

        // Update view center
        view.center = newCenter
    
    else if gesture.state == .ended 
       ...
    

【讨论】:

【参考方案4】:

你不需要声明_priorPoint;

就我而言,我只希望视图水平移动,所以我只更改 x 坐标。

这是我的解决方案:

    if (longpressGestRec.state == UIGestureRecognizerStateChanged)
    
        UIView *view = longpressGestRec.view;

        // Location of the touch within the view.
        CGPoint point = [longpressGestRec locationInView:view];

        // Calculate new X position based on the amount the gesture
        // has moved plus the size of the view we want to move.
        CGFloat newXLoc = (item.frame.origin.x + point.x) - (item.frame.size.width / 2);
        [item setFrame:CGRectMake(newXLoc,
                                  item.frame.origin.y,
                                  item.frame.size.width,
                                  item.frame.size.height)];
    

【讨论】:

您的解决方案仅适用于手指后的UIView。想象一下,你从一张图片的一角开始UILongPress,你想向左滑动,这张图片会跳到你手指的位置。就我而言,我必须使用_priorPoint 解决方案。【参考方案5】:

感谢 Hari Kunwar 的 Swift 代码,但 longPressAction 函数没有正确定义。

这是一个改进的版本:

@objc func longPressAction(gesture: UILongPressGestureRecognizer)  
    if gesture.state == UIGestureRecognizerState.began 
    
    else if gesture.state == .changed 
        guard let view = gesture.view else 
            return
        
        let location = gesture.location(in: self.view)
        view.center = CGPoint(x:view.center.x + (location.x - view.center.x),
                                          y:view.center.y + (location.y - view.center.y))
    
    else if gesture.state == UIGestureRecognizerState.ended
    

【讨论】:

以上是关于将长按手势和拖动手势结合在一起的主要内容,如果未能解决你的问题,请参考以下文章

iOS 手势操作:拖动捏合旋转点按长按轻扫自定义

Android:如何在listView上的项目中结合滑动手势和长按

Swift基础--手势识别(双击捏旋转拖动划动长按)

一起识别长按和平移手势识别器

结合向下滑动和长按

UICollectionView 中的长按和平移手势