Wie verwende ich UIPanGestureRecognizer, um ein Objekt zu verschieben? iPhone / iPad


80

Es gibt mehrere Beispiele für die UIPanGestureRecognizerKlasse. Zum Beispiel habe ich gelesen das , und ich bin nach wie vor nicht in der Lage , es zu benutzen ...

In der Nib-Datei, an der ich arbeite, befindet sich ein UIView(weißes Rechteck auf dem Bild), das ich mit dieser Klasse ziehen möchte:

Geben Sie hier die Bildbeschreibung ein

und in meine .m Datei habe ich gelegt:

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

und diese Methode wird nicht ausgeführt, wenn ich die Maus über die UIView. Ich habe auch versucht zu platzieren:

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

Und diese Methode wird auch nicht ausgeführt. Vielleicht irre ich mich, aber ich denke, diese Methode sollte wie die - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)eventMethode funktionieren , bei der ich diese Methode nur platzieren muss, und sie wird aufgerufen, wenn es Berührungen gibt.

Was mache ich falsch? Vielleicht muss ich eine Verbindung zu dieser Methode herstellen? Wenn ja, wie kann ich das machen?

Antworten:


145

Ich habe das Tutorial Arbeiten mit UIGestureRecognizers gefunden und denke, das ist es, wonach ich suche. Es hat mir geholfen, die folgende Lösung zu finden:

-(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
Tolle!! Ich liebe die Berechnung der AnimationDuration, funktioniert super.
白 目

39
Wenn Sie den Absender move: (id) in move ändern: (UIPanGestureRecognizer *) sender, müssen Sie nicht all diese hässlichen Typografien durchführen.
Wex

1
Diese Lösung funktioniert nicht für UISwitch. Außerdem habe ich versucht, die Methoden touchBegan und touchMoved zu implementieren, konnte jedoch UISwitch nicht verschieben. Können Sie mir bitte sagen, wie ich UISwitch nur durch Ziehen verschieben kann?
DShah

2
Denken Sie daran, userInteractionEnabled = YES für die Ansicht zu haben, der die Gestenerkennung zugeordnet ist.
Lukas Kalinski

1
Was sind firstX und firstY?
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];
}

makelloser Sieg!
ManuelBetancurt

1
Ich kann nicht mit der Einfachheit argumentieren, aber diese Lösung hat ein Problem: Sobald Sie Ihren Finger nach unten legen, um die Geste zu starten, image1wird möglicherweise ziemlich weit springen, so dass seine Mitte unter Ihrem Finger liegt. Besser image1.centerdurch die panÜbersetzung des für eine flüssigere und Standard-Erfahrung anpassen .
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
Denn CGPointMake(0, 0)du kannst schreiben CGRectZero.
Bedeutung-Angelegenheiten

3
@ Bedeutungsangelegenheiten Meinst du nicht CGPointZero?
Mylogon

2
@mylogon Du hast absolut recht. Ich werde einige Ihrer Antworten als meinen Dank aussprechen.
Bedeutung-Angelegenheiten

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

Swift 2-Version der @ MS AppTech-Antwort

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

Ein paar Jahre später warf ich meinen Hut in den Ring.

Muss die Anfangsmitte der Bildansicht speichern:

var panBegin: CGPoint.zero

Aktualisieren Sie dann das neue Zentrum mithilfe einer Transformation:

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

Die Swift 2 Version:

// 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")
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.