2010-05-06 3 views
4

Je me demande quelle est la meilleure façon d'implémenter des mouvements de rotation basés sur la rotation dans mon application iPhone.Implémentation de la rotation tactile dans le cacao tactile

J'ai un UIView que je souhaite faire pivoter autour de son centre, lorsque le doigt de l'utilisateur touche la vue et la déplace. Pensez-y comme un cadran qui doit être réglé avec le doigt.

La question fondamentale se résume à:

1) Si je me souviens l'angle initial et transformer quand touchesBegan est appelée, puis chaque fois touchesMoved est appelé appliquer une nouvelle transformation à la vue en fonction de la position actuelle le doigt, par exemple, quelque chose comme:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 

    UITouch *touch = [touches anyObject]; 
    CGPoint currentPoint = [touch locationInView:self]; //current position of touch 

if (([touch view] == self) 
    && [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS //middle is centre of view 
    && [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //will be rotation gesture 

    //remember state of view at beginning of touch 
    CGPoint top = CGPointMake(self.middle.x, 0); 
    self.initialTouch = currentPoint; 
    self.initialAngle = angleBetweenLines(self.middle, top, self.middle, currentPoint); 
    self.initialTransform = self.transform; 
} 
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 

    UITouch *touch = [touches anyObject]; 
    CGPoint currentPoint = [touch locationInView:self]; //current position of touch 

    if (([touch view] == self) 
    && [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS 
    && [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //a rotation gesture 

    //rotate tile 
    float newAngle = angleBetweenLines(self.middle, CGPointMake(self.middle.x, 0), self.middle, currentPoint); //touch angle 
    float angleDif = newAngle - self.initialAngle; //work out dif between angle at beginning of touch and now. 
    CGAffineTransform newTransform = CGAffineTransformRotate(self.initialTransform, angleDif); //create new transform 
    self.transform = newTransform; //apply transform. 
} 

OU

2) Si je me souviens simplement de la dernière position connue/angle et faire pivoter la vue en fonction de la différence d'angle entre cela et maintenant, par exemple, :La deuxième option a plus de sens pour moi, mais elle ne donne pas de résultats très agréables (mises à jour jaggy et rotations non lisses). Quel est le meilleur (le cas échéant), en termes de performance?

À la votre!

Répondre

0

Avez-vous envisagé d'utiliser UIRotationGestureRecognizer? On dirait que cela a déjà une logique et pourrait rendre les choses plus simples.

+0

Alors que les UIGestureRecognizers sont sympa et maniable, ils ont un inconvénient: il faut souvent environ 10 pixels de mouvement jusqu'à ce qu'ils reconnaissent leur geste. J'ai trouvé cela inacceptable dans une application graphique liée à moi, alors je le fais à l'ancienne. Cela devient encore plus délicat si vous voulez reconnaître plusieurs gestes. Savoir dessiner des diagrammes d'état aide beaucoup ... –

3

Il est en réalité beaucoup plus simple que ce que vous avez essayé.

Vous avez besoin de trois points de données:

  • L'origine de votre point de vue.
  • L'emplacement de la touche actuelle
  • L'emplacement de la touche précédente

L'objet tactile est passé à vous contient en fait le dernier emplacement de contact. Donc vous n'avez pas besoin de le suivre.

Tout ce que vous avez à faire est de calculer l'angle entre deux lignes:

  • origine à courant tactile
  • Origin à toucher Précédent

ensuite convertir en radians et l'utiliser dans votre CGAffineTransformRotate(). Faites tout cela dans vos contactsManipulateur.

Voici une fonction pour calculer ce que vous avez juste besoin que:

static inline CGFloat angleBetweenLinesInRadians(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) { 

    CGFloat a = line1End.x - line1Start.x; 
    CGFloat b = line1End.y - line1Start.y; 
    CGFloat c = line2End.x - line2Start.x; 
    CGFloat d = line2End.y - line2Start.y; 

    CGFloat line1Slope = (line1End.y - line1Start.y)/(line1End.x - line1Start.x); 
    CGFloat line2Slope = (line2End.y - line2Start.y)/(line2End.x - line2Start.x); 

    CGFloat degs = acosf(((a*c) + (b*d))/((sqrt(a*a + b*b)) * (sqrt(c*c + d*d)))); 


    return (line2Slope > line1Slope) ? degs : -degs;  
} 

Avec l'aimable autorisation de Jeff LaMarche à:

http://iphonedevelopment.blogspot.com/2009/12/better-two-finger-rotate-gesture.html

Exemple:

UITouch *touch = [touches anyObject]; 
CGPoint origin = [view center]; 
CGFloat angle = angleBetweenLinesInRadians(origin, [touch previousLocationInView:self.superview.superview], origin, [touch locationInView:self.superview.superview]);