【问题标题】:How to use UIPanGestureRecognizer to move object? iPhone/iPad如何使用 UIPanGestureRecognizer 移动对象? iPhone/iPad
【发布时间】:2011-10-04 02:24:21
【问题描述】:

UIPanGestureRecognizer 类有几个示例。比如我读过this,还是不能用……

在我正在处理的 nib 文件上,我有一个 UIView(图像上的白色矩形),我希望用该类拖动它:

在我放置的 .m 文件中:

- (void)setTranslation:(CGPoint)translation inView:(UIView *)view
{
    NSLog(@"Test to see if this method gets executed");
}

当我将鼠标拖过UIView 时,该方法不会被执行。我也试过放置:

- (void)pan:(UIPanGestureRecognizer *)gesture
{
    NSLog(@"testing");
}

而且该方法也不会被执行。也许我错了,但我认为这种方法应该像 - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 方法一样工作,我只需放置该方法,只要有触摸它就会被调用。

我做错了什么?也许我必须与该方法建立联系?如果是这样,我该怎么做?

【问题讨论】:

    标签: iphone objective-c ipad drag


    【解决方案1】:

    我找到了教程Working with UIGestureRecognizers,我认为这就是我要找的。它帮助我想出了以下解决方案:

    -(IBAction) someMethod {
        UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(move:)];
        [panRecognizer setMinimumNumberOfTouches:1];
        [panRecognizer setMaximumNumberOfTouches:1];
        [ViewMain addGestureRecognizer:panRecognizer];
        [panRecognizer release];
    }
    
    -(void)move:(UIPanGestureRecognizer*)sender {
        [self.view bringSubviewToFront:sender.view];
        CGPoint translatedPoint = [sender translationInView:sender.view.superview];
    
        if (sender.state == UIGestureRecognizerStateBegan) {
            firstX = sender.view.center.x;
            firstY = sender.view.center.y;
        }
    
    
        translatedPoint = CGPointMake(sender.view.center.x+translatedPoint.x, sender.view.center.y+translatedPoint.y);
    
        [sender.view setCenter:translatedPoint];
        [sender setTranslation:CGPointZero inView:sender.view];
    
        if (sender.state == UIGestureRecognizerStateEnded) {
            CGFloat velocityX = (0.2*[sender velocityInView:self.view].x);
            CGFloat velocityY = (0.2*[sender velocityInView:self.view].y);
    
            CGFloat finalX = translatedPoint.x + velocityX;
            CGFloat finalY = translatedPoint.y + velocityY;// translatedPoint.y + (.35*[(UIPanGestureRecognizer*)sender velocityInView:self.view].y);
    
            if (finalX < 0) {
                finalX = 0;
            } else if (finalX > self.view.frame.size.width) {
                finalX = self.view.frame.size.width;
            }
    
            if (finalY < 50) { // to avoid status bar
                finalY = 50;
            } else if (finalY > self.view.frame.size.height) {
                finalY = self.view.frame.size.height;
            }
    
            CGFloat animationDuration = (ABS(velocityX)*.0002)+.2;
    
            NSLog(@"the duration is: %f", animationDuration);
    
            [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:animationDuration];
            [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
            [UIView setAnimationDelegate:self];
            [UIView setAnimationDidStopSelector:@selector(animationDidFinish)];
            [[sender view] setCenter:CGPointMake(finalX, finalY)];
            [UIView commitAnimations];
        }
    }
    

    【讨论】:

    • 太棒了!我喜欢animationDuration的计算,效果很好。
    • 如果您将 move:(id)sender 更改为 move:(UIPanGestureRecognizer*)sender,您就不必进行所有丑陋的类型转换。
    • 此解决方案不适用于 UISwitch。我还尝试实现 touchesBegan、touchesMoved 方法但无法移动 UISwitch。你能告诉我如何仅通过拖动来移动 UISwitch 吗??
    • 记得为手势识别器关联的视图设置 userInteractionEnabled=YES。
    • 什么是firstX和firstY?
    【解决方案2】:
    UIPanGestureRecognizer * pan1 = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(moveObject:)];
    pan1.minimumNumberOfTouches = 1;
    [image1 addGestureRecognizer:pan1];
    
    -(void)moveObject:(UIPanGestureRecognizer *)pan;
    {
     image1.center = [pan locationInView:image1.superview];
    }
    

    【讨论】:

    • 完美的胜利!
    • 不能与简单性争论,但这个解决方案有一个问题:一旦你放下手指开始手势,image1 会跳,可能很远,所以它的中心在你的手指下。最好通过pan 的翻译调整image1.center,以获得更流畅和标准的体验。
    【解决方案3】:
    -(IBAction)Method
    {
          UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
          [panRecognizer setMinimumNumberOfTouches:1];
          [panRecognizer setMaximumNumberOfTouches:1];
          [ViewMain addGestureRecognizer:panRecognizer];
          [panRecognizer release];
    }
    - (Void)handlePan:(UIPanGestureRecognizer *)recognizer
    {
    
         CGPoint translation = [recognizer translationInView:self.view];
         recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, 
                                         recognizer.view.center.y + translation.y);
         [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
    
         if (recognizer.state == UIGestureRecognizerStateEnded) {
    
             CGPoint velocity = [recognizer velocityInView:self.view];
             CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
             CGFloat slideMult = magnitude / 200;
             NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);
    
             float slideFactor = 0.1 * slideMult; // Increase for more of a slide
             CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor), 
                                         recognizer.view.center.y + (velocity.y * slideFactor));
             finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
             finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
    
             [UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                 recognizer.view.center = finalPoint;
             } completion:nil];
    
        }
    
    }
    

    【讨论】:

    • 对于CGPointMake(0, 0),你可以写CGRectZero
    • @meaning-matters 你不是说CGPointZero吗?
    • @mylogon 你说得对。我会把你的一些答案作为我的谢意。
    【解决方案4】:
    if ([recognizer state] == UIGestureRecognizerStateChanged)    
    {
        CGPoint translation1 = [recognizer translationInView:main_view];
        img12.center=CGPointMake(img12.center.x+translation1.x, img12.center.y+ translation1.y);
        [recognizer setTranslation:CGPointMake(0, 0) inView:main_view];
    
        recognizer.view.center=CGPointMake(recognizer.view.center.x+translation1.x, recognizer.view.center.y+ translation1.y);
    }
    
    -(void)move:(UIPanGestureRecognizer*)recognizer
    {
        if ([recognizer state] == UIGestureRecognizerStateChanged)    
        {
            CGPoint translation = [recognizer translationInView:self.view];
            recognizer.view.center=CGPointMake(recognizer.view.center.x+translation.x, recognizer.view.center.y+ translation.y);
            [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
        }
    }
    

    【讨论】:

      【解决方案5】:

      @MS AppTech 答案的 swift 2 版本

      func handlePan(panGest : UIPanGestureRecognizer) {
      let velocity : CGPoint = panGest.velocityInView(self.view);
              let magnitude : CGFloat = CGFloat(sqrtf((Float(velocity.x) * Float(velocity.x)) + (Float(velocity.y) * Float(velocity.y))));
              let slideMult :CGFloat = magnitude / 200;
              //NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);
      
              let slideFactor : CGFloat = 0.1 * slideMult; // Increase for more of a slide
              var finalPoint : CGPoint = CGPointMake(panGest.view!.center.x + (velocity.x * slideFactor),
                                               panGest.view!.center.y + (velocity.y * slideFactor));
              finalPoint.x = min(max(finalPoint.x, 0), self.view.bounds.size.width);
              finalPoint.y = min(max(finalPoint.y, 0), self.view.bounds.size.height);
      
              UIView.animateWithDuration(Double(slideFactor*2), delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
                  panGest.view!.center = finalPoint;
                  }, completion: nil)
      }
      

      【讨论】:

        【解决方案6】:

        @Tono Nam 在 Swift 5 中的回答(已接受)

        func someMethod() {
            let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(move))
            panGestureRecognizer.minimumNumberOfTouches = 1
            panGestureRecognizer.maximumNumberOfTouches = 1
            view.addGestureRecognizer(panGestureRecognizer)
        }
        
        @objc func move(sender: UIPanGestureRecognizer) {
            guard let senderView = sender.view else { return }
            
            self.view.bringSubviewToFront(senderView)
            var translatedPoint: CGPoint = sender.translation(in: senderView.superview)
            
            if(sender.state == .began) {
                let firstX = senderView.center.x
                let firstY = senderView.center.y
            }
            
            translatedPoint = CGPoint(x: senderView.center.x + translatedPoint.x, y: senderView.center.y + translatedPoint.y)
            senderView.center = translatedPoint
            sender.setTranslation(.zero, in: senderView)
            
            if(sender.state == .ended) {
                let velocityX: CGFloat = (0.2 * sender.velocity(in: self.view).x)
                let velocityY: CGFloat = (0.2 * sender.velocity(in: self.view).y)
                
                var finalX: CGFloat = translatedPoint.x + velocityX
                var finalY: CGFloat = translatedPoint.y + velocityY
                
                if(finalX < 0) {
                    finalX = 0
                } else if (finalX > self.view.frame.size.width) {
                    finalX = self.view.frame.size.width;
                }
                
                if (finalY < 50) { // to avoid status bar
                    finalY = 50;
                } else if (finalY > self.view.frame.size.height) {
                    finalY = self.view.frame.size.height;
                }
                
                let animationDuration: TimeInterval = TimeInterval(abs(velocityX) * 0.0002 + 0.2)
                print("the animation duration is \(animationDuration)")
                
                UIView.animate(withDuration: animationDuration, delay: 0, options: .curveEaseOut) {
                    senderView.center = CGPoint(x: finalX, y: finalY)
                } completion: { completed in
                    // call animationDidFinish completion handler here
                }
            }
        }
        

        【讨论】:

          【解决方案7】:

          几年后把我的帽子扔进戒指。

          需要保存图像视图的开始中心:

          var panBegin: CGPoint.zero
          

          然后使用变换更新新中心:

          if recognizer.state == .began {
               panBegin = imageView!.center
          
          } else if recognizer.state == .ended {
              panBegin = CGPoint.zero
          
          } else if recognizer.state == .changed {
              let translation = recognizer.translation(in: view)
              let panOffsetTransform = CGAffineTransform( translationX: translation.x, y: translation.y)
          
              imageView!.center = panBegin.applying(panOffsetTransform)
          }
          

          【讨论】:

            【解决方案8】:

            Swift 2 版本:

            // start detecting pan gesture
            let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(TTAltimeterDetailViewController.panGestureDetected(_:)))
            panGestureRecognizer.minimumNumberOfTouches = 1
            self.chartOverlayView.addGestureRecognizer(panGestureRecognizer)
            
            func panGestureDetected(panGestureRecognizer: UIPanGestureRecognizer) {
                print("pan gesture recognized")
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多