web-dev-qa-db-fra.com

UIPinchGestureRecognizer positionne la vue pincée entre les deux doigts

J'ai réussi à implémenter un pincement d'un zoom d'une vue. Cependant, la vue ne se positionne pas là où je le souhaitais. Pour les stackoverflowers avec un iPad, je voudrais que ma vue soit centrée comme sur l'iPad Photos.app: lorsque vous pincez et zoomez sur un album, les photos se présentent dans une vue qui s'agrandit. Cette vue est approximativement centrée avec le coin supérieur droit sur le premier doigt et le doigt inférieur gauche sur l'autre doigt. Je l'ai mélangé avec un identificateur de panoramique, mais de cette façon, l'utilisateur doit toujours pincer, puis effectuer un panoramique pour régler.

Voici une explication tellement graphique, je pourrais poster une vidéo de mon application si ce n'est pas clair (pas de secret, j'essaie de reproduire le Photos.app de l'iPad ...)

Donc pour une position initiale des doigts, en commençant le zoom:

enter image description here

Il s'agit du cadre réel "zoomé" pour l'instant. Le carré est plus grand, mais la position est en dessous des doigts

given the start position

Voici ce que j'aimerais avoir: même taille, mais Origin.x et y différents:

enter image description here

(désolé pour mes piètres compétences photoshop ^^)

39
Thomas Joulin

Vous pouvez obtenir le CGPoint du milieu entre deux doigts via le code suivant dans la méthode handlingPinchGesture.

CGPoint point = [sender locationInView:self];

Toute ma méthode handlePinchGesture est ci-dessous.

/*
instance variables

CGFloat lastScale;
CGPoint lastPoint;
*/

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)sender {
    if ([sender numberOfTouches] < 2)
        return;

    if (sender.state == UIGestureRecognizerStateBegan) {
        lastScale = 1.0;
        lastPoint = [sender locationInView:self];
    }

    // Scale
    CGFloat scale = 1.0 - (lastScale - sender.scale);
    [self.layer setAffineTransform:
        CGAffineTransformScale([self.layer affineTransform], 
                               scale, 
                               scale)];
    lastScale = sender.scale;

    // Translate
    CGPoint point = [sender locationInView:self];
    [self.layer setAffineTransform:
        CGAffineTransformTranslate([self.layer affineTransform], 
                                   point.x - lastPoint.x, 
                                   point.y - lastPoint.y)];
    lastPoint = [sender locationInView:self];
}
43
mishimay

Jetez un œil au exemple de projet Touches . Plus précisément, ces méthodes pourraient vous aider:

// scale and rotation transforms are applied relative to the layer's anchor point
// this method moves a gesture recognizer's view's anchor point between the user's fingers
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        UIView *piece = gestureRecognizer.view;
        CGPoint locationInView = [gestureRecognizer locationInView:piece];
        CGPoint locationInSuperview = [gestureRecognizer locationInView:piece.superview];

        piece.layer.anchorPoint = CGPointMake(locationInView.x / piece.bounds.size.width, locationInView.y / piece.bounds.size.height);
        piece.center = locationInSuperview;
    }
}

// scale the piece by the current scale
// reset the gesture recognizer's rotation to 0 after applying so the next callback is a delta from the current scale
- (void)scalePiece:(UIPinchGestureRecognizer *)gestureRecognizer
{
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
        [gestureRecognizer view].transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
        [gestureRecognizer setScale:1];
    }
}
11
Felix