Làm thế nào để sử dụng UIPanGestureRecognizer để di chuyển đối tượng? iPhone / iPad


80

Có một số ví dụ về UIPanGestureRecognizerlớp học. Ví dụ: tôi đã đọc cái này và tôi vẫn không thể sử dụng nó ...

Trên tệp nib mà tôi đang làm việc, tôi có một UIView(hình chữ nhật màu trắng trên hình ảnh) mà tôi muốn kéo theo lớp đó:

nhập mô tả hình ảnh ở đây

và trong tệp .m của tôi, tôi đã đặt:

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

và phương thức đó không được thực thi khi tôi kéo chuột qua UIView. Tôi cũng đã thử đặt:

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

Và phương thức đó cũng không được thực thi. Có thể tôi sai nhưng tôi nghĩ phương thức này sẽ hoạt động giống như - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)eventphương thức mà tôi chỉ cần đặt phương thức đó và nó sẽ được gọi bất cứ khi nào có chạm.

Tôi đang làm gì sai? Có lẽ tôi phải vẽ một kết nối đến phương pháp đó? Nếu vậy làm thế nào tôi có thể làm điều đó?

Câu trả lời:


145

Tôi đã tìm thấy hướng dẫn Làm việc với UIGestureRecognizers và tôi nghĩ đó là những gì tôi đang tìm kiếm. Nó đã giúp tôi đưa ra giải pháp sau:

-(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];
    }
}

1
Kinh ngạc!! Tôi thích tính toán của animationDuration, hoạt động tuyệt vời.
最 白 目

39
Nếu bạn thay đổi chuyển: (id) người gửi thành chuyển: (UIPanGestureRecognizer *) người gửi, bạn không phải thực hiện tất cả những thao tác đánh máy xấu xí đó.
Wex

1
Giải pháp này không hoạt động đối với UISwitch. Ngoài ra, tôi đã thử triển khai các phương thức touchBegan, touchMoved nhưng không thể di chuyển UISwitch. Bạn có thể vui lòng cho tôi biết làm thế nào tôi có thể di chuyển UISwitch chỉ bằng cách Kéo ??
DShah

2
Hãy nhớ có userInteractionEnabled = YES cho chế độ xem có liên kết với trình nhận dạng cử chỉ.
Lukas Kalinski

1
FirstX và firstY là gì?
Krekin

39
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];
}

chiến thắng hoàn mỹ!
manuelBetancurt

1
Không thể tranh cãi về sự đơn giản, nhưng giải pháp này có một vấn đề: ngay khi bạn đặt ngón tay xuống để bắt đầu cử chỉ, image1nó sẽ nhảy, có khả năng khá xa, do đó tâm của nó nằm dưới ngón tay của bạn. Tốt hơn nên điều chỉnh image1.centerbằng panbản dịch để có trải nghiệm chuẩn và trôi chảy hơn.
sartak

25
-(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];

    }

}

3
Đối với CGPointMake(0, 0)bạn có thể viết CGRectZero.
ý nghĩa-vấn đề

3
@ ý nghĩa-vấn đề Ý bạn không phải là CGPointZero?
mylogon

2
@mylogon Bạn hoàn toàn đúng. Tôi sẽ đưa ra một số câu trả lời của bạn như lời cảm ơn của tôi.
ý nghĩa-vấn đề

1
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];
    }
}

1

phiên bản nhanh chóng 2 của câu trả lời @MS AppTech

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)
}

0

Một vài năm sau đó, tôi đã đưa chiếc mũ của mình lên sàn đấu.

Sẽ cần phải lưu tâm đầu của chế độ xem hình ảnh:

var panBegin: CGPoint.zero

Sau đó, cập nhật trung tâm mới bằng cách sử dụng một biến đổi:

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)
}

-2

Phiên bản 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")
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.