Sens de rotation avec CGAffineTransformIdentity ? [résolu]

MAGEMAGE Membre
juin 2010 modifié dans API UIKit #1
Petite question sur les rotations :
J'ai un cercle que je fais tourner sur lui-même avec un touchesMoved.
Lorsque je lâche, il doit revenir en position initiale.

Pas de problème lorsque la rotation est inférieur à  180, il tourne dans le bon sens (sens inverse des aiguilles d'une montre) avec ce code :

- (void)animateCadranViewToCenter {	<br />[UIView setAnimationBeginsFromCurrentState:YES];<br />[UIView beginAnimations:nil context:NULL];<br />[UIView setAnimationDuration:0.5];<br />cadran.transform = CGAffineTransformIdentity;<br />}



Mais ensuite, (si la rotation est supérieure à  180°) il part dans l'autre sens.
Du coup j'ai essayé de le faire en deux temps en ajoutant un angle :
[UIView setAnimationBeginsFromCurrentState:YES];<br />[UIView beginAnimations:nil context:NULL];<br />[UIView setAnimationDuration:0.2];<br />cadran.transform = CGAffineTransformRotate(cadran.transform, degreesToRadians(-30));<br />[UIView commitAnimations];<br />[self performSelector:@selector(animateCadranViewToCenter) withObject:nil afterDelay:0.2];


Mais l'animation est alors effectuée en deux temps et il y a un ralentissement au moment du changement d'animation.

Existe-il un autre moyen pour l'obliger à  partir dans le sens voulu ?

Réponses

  • Philippe49Philippe49 Membre
    09:29 modifié #2
    Pour une animation, on peut donner une liste de valeurs intermédiaires via une NSArray de NSValue. On anime alors directement le layer ("le calque" dit on en dessin) de la vue

    <br />	CAKeyframeAnimation * transformAnimation=[CAKeyframeAnimation animationWithKeyPath:@&quot;transform&quot;];<br />	transformAnimation.values=arrayOfValuesOfCATransform3D;<br />	transformAnimation.duration=mduration;	<br />	[self.layer addAnimation:animation forKey:nil];<br />
    


    avec arrayOfValuesOfCATransform3D une NSArray contenant des NSValue

    NSArray * array=[NSArray arrayWithObjects:<br />		[NSValue valueWithCATransform3D:CATransform3DIdentity],<br />		[NSValue valueWithCATransform3D:CATransform3DMakeRotation(..,...,...,...)],<br />		...,<br />		nil];<br />
    
  • MAGEMAGE Membre
    09:29 modifié #3
    Merci pour ta réponse, Philippe.

    Bon, à  part que je n'arrive plus à  faire défiler l'animation (la roue passe d'un état à  un autre d'un coup)...

    C'est que l'animation de retour (CATransform3DIdentity) est un retour sur l'animation précédente. La roue ne revient pas au point de départ.

    J'avais aussi essayé de container les deux animations, mais le passage d'une animation à  l'autre était aussi visible.
  • Philippe49Philippe49 Membre
    09:29 modifié #4
    Je t'assure qui si tu choisis les bons angles intermédiaires cela marche très bien.

    Mais on a déjà  résolu ce problème non ?
  • MAGEMAGE Membre
    09:29 modifié #5
    J'ai rien résolu du tout  :'(

    Je suis une buse, mais j'y arrive pas.

    J'ai ce code :
    NSArray * arrayOfValuesOfCATransform3D=[NSArray arrayWithObjects:<br />	[NSValue valueWithCATransform3D:CATransform3DMakeRotation(-150,0.0,0.0,0.0)],<br />	[NSValue valueWithCATransform3D:CATransform3DIdentity],nil];<br /><br />	<br />CAKeyframeAnimation * transformAnimation=[CAKeyframeAnimation animationWithKeyPath:@&quot;transform&quot;];<br />transformAnimation.values=arrayOfValuesOfCATransform3D;<br />transformAnimation.duration=2.0;	<br />[cadran.layer addAnimation:transformAnimation forKey:nil];
    


    Mais je n'ai toujours pas d'animation

    Etrangement, avec ceci :
    CATransform3D rotationTransform = CATransform3DMakeRotation(120, 0, 0, 0.0);	<br /><br />CABasicAnimation* rotationAnimation;<br />rotationAnimation = [CABasicAnimation animationWithKeyPath:@&quot;transform&quot;];<br />rotationAnimation.toValue = [NSValue valueWithCATransform3D:rotationTransform];<br />rotationAnimation.duration = 2.0;<br />				<br />[cadran.layer addAnimation:rotationAnimation forKey:@&quot;rotationAnimation&quot;];
    


    J'ai une animation, mais le cadran reviens à  la position où je l'ai lâché et non où il est parti.

    ... je vais chercher encore. En tous cas, merci pour la piste.
  • Philippe49Philippe49 Membre
    09:29 modifié #6
    Allez un petit essai
  • Philippe49Philippe49 Membre
    09:29 modifié #7
    dans 1249372586:

    Etrangement, avec ceci :
    CATransform3D rotationTransform = CATransform3DMakeRotation(120, 0, 0, 0.0);	<br /><br />CABasicAnimation* rotationAnimation;<br />rotationAnimation = [CABasicAnimation animationWithKeyPath:@&quot;transform&quot;];<br />rotationAnimation.toValue = [NSValue valueWithCATransform3D:rotationTransform];<br />rotationAnimation.duration = 2.0;<br />				<br />[cadran.layer addAnimation:rotationAnimation forKey:@&quot;rotationAnimation&quot;];
    


    J'ai une animation, mais le cadran reviens à  la position où je l'ai lâché et non où il est parti.

    ... je vais chercher encore. En tous cas, merci pour la piste.

    Rajoute cadran.layer.transform=rotationTransform; pour fixer l'état final.
  • MAGEMAGE Membre
    09:29 modifié #8
    Rien à  faire  :crackboom:-

    J'ai refait un projet à  zéro pour voir, mais j'ai les mêmes problèmes. Je le mets en pièce jointe au cas où...

    Grâce à  ton petit essai, j'ai une animation. Mais elle ne part pas au même point du lâché et arrive toujours au point du lâché.

    J'aimerai que le cadran démarre au point lâché et arrive au point avant le touché.
  • Philippe49Philippe49 Membre
    août 2009 modifié #9
    Voilà  un code qui permet d'avoir l'angle courant qui contient le nombre de tours : si tu as fait deux tours et 1/8 , currentAngle vaut 4.Pi+Pi/4  . C'est ce qu'on appelé dans un post précédent une détermination continue de l'angle, sans le saut de 2Pi qui apparaà®t en -Pi.
    initialAngle est l'angle par rapport à  l'horizontal lors du touchesBegin.

    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {<br />	UITouch * touch = [touches anyObject];<br />	CGPoint currentLocation=[touch locationInView:self.view];<br />	<br />	// Lors du déplacement sur le cadran, il tourne <br />	if ((CGRectContainsPoint([cadran frame], currentLocation)) ) {		<br />		CGFloat newAngle = atan2(currentLocation.y - cadran.center.y, currentLocation.x - cadran.center.x) - initialAngle;	<br />		long k=lrint((currentAngle-newAngle)/(2.*M_PI));<br />		currentAngle=newAngle+2.*M_PI*k;<br />		cadran.transform = CGAffineTransformMakeRotation(currentAngle);<br />	}<br />}
    


    Dès lors il ne reste plus qu'à  échantillonner de currentAngle à  0 pour revenir en arrière. On peut prendre un pas régulier de quelques degrés, de toutes façons, CAKeyframeAnimation rééchantillonne ensuite selon le timer qu'il se donne. La durée de l'animation est à  proportionner à  la valeur de |currentAngle| . Attention currentAngle est positif ou négatif.

    Lorsque currentAngle>0, un truc dans le genre quoi :
    for(nStep=0;currentAngle&gt;step;nStep++,currentAngle-=step){<br />			NSValue * value= [NSValue valueWithCATransform3D:CATransform3DMakeRotation(currentAngle,0.,0.0,1.0)];<br />			[array addObject:value];<br />		}<br />		[array addObject:[NSValue valueWithCATransform3D:CATransform3DIdentity]];
    
       
  • MAGEMAGE Membre
    09:29 modifié #10
    Merci pour tous ces essais, mais chez moi, l'animation "touchesMoved" ne fonctionne plus avec ce code, elle saute.

    si tu as fait deux tours

    Je ne fais au maximum que 350°

    Pour le reste, j'entrevois ma grande incompétence. De ma petite question d'ordre cosmétique, je me retrouve dans des méandres de codes très difficile à  déchiffrer. B)

    Je vais reprendre la doc et les posts précédents avant de te prendre plus de ton temps... encore merci Philippe
  • Philippe49Philippe49 Membre
    août 2009 modifié #11
    dans 1249483818:

    Merci pour tous ces essais, mais chez moi, l'animation "touchesMoved" ne fonctionne plus avec ce code, elle saute.

    Cela doit être une question de bon dosage avec step et la durée de l'animation

    dans 1249483818:

    si tu as fait deux tours

    Je ne fais au maximum que 350°

    Le problème est le même, il faut passer la barre des 180° et retourner dans le bon sens. Limiter à  un tour ne simplifie pas.
    une video de la réalisation (un peu lourde à  charger)
  • MAGEMAGE Membre
    09:29 modifié #12
    Le lien n'est pas fonctionnel
  • Philippe49Philippe49 Membre
    09:29 modifié #13
    Réparé !
    J'ai un temps de connexion faramineux actuellement avec le site rien qu'en changeant de page . Toi aussi ?
  • MAGEMAGE Membre
    09:29 modifié #14
    J'ai pas remarqué.
  • MAGEMAGE Membre
    09:29 modifié #15
    AAAAARGH ! :o Ben vi. C'est ça.

    Bon, je m'y remets  >:(
  • MAGEMAGE Membre
    09:29 modifié #16
    J'ai un temps de connexion faramineux actuellement avec le site rien qu'en changeant de page

    C'est la rançon du succès  ;)

    Bon, c'est le pétchi... mais j'en suis là  (Pas taper):
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [super touchesBegan:touches withEvent:event];
    UITouch *touch = [touches anyObject];
    // touché 1 = centre du cadran
    touch1 = cadran.center;
    // touché 2 = touché du doigt
    touch2 = [touch locationInView:self.view];
    initialAngle= atan2(touch2.y - touch1.y, touch2.x - touch1.x) * 180 / M_PI;
    }


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

    UITouch * touch = [touches anyObject];
    CGPoint currentLocation=[touch locationInView:self.view];

    // Lors du déplacement sur le cadran, il tourne
    if ((CGRectContainsPoint([cadran frame], currentLocation)) ) {
    CGFloat newAngle = atan2(currentLocation.y - cadran.center.y, currentLocation.x - cadran.center.x)-initialAngle;
    NSLog(@float : %f,initialAngle);

    long k=lrint((currentAngle-newAngle)/(2.*M_PI));
    currentAngle=newAngle+2.*M_PI*k;
    cadran.transform = CGAffineTransformMakeRotation(currentAngle);
    }

    }


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

    int nStep;

    NSMutableArray * array=[NSMutableArray array];

    int step;
    for(nStep=0;currentAngle>step;nStep++,currentAngle-=step){
    NSValue * value= [NSValue valueWithCATransform3D:CATransform3DMakeRotation(currentAngle,0.,0.0,1.0)];
    [array addObject:value];
    }
    [array addObject:[NSValue valueWithCATransform3D:CATransform3DIdentity]];


    CAKeyframeAnimation * transformAnimation=[CAKeyframeAnimation animationWithKeyPath:@transform];
    transformAnimation.values=array;
    transformAnimation.duration=5.0;
    [cadran.layer addAnimation:transformAnimation forKey:nil];

    }


    J'ai l'impression que l'initialAngle n'est pas pris en compte, car même si je supprime le -initialAngle, j'ai le même comportement.
  • Philippe49Philippe49 Membre
    août 2009 modifié #17
    Déjà  les calculs se font en radians :
    initialAngle= atan2(touch2.y - touch1.y, touch2.x - touch1.x) * 180 / M_PI;

  • Philippe49Philippe49 Membre
    09:29 modifié #18

      int step;
      for(nStep=0;currentAngle>step;nStep++,currentAngle-=step){


    Et puis step devrait être un CGFloat et être initialisé
  • MAGEMAGE Membre
    09:29 modifié #19
    Ah, ben j'ai encore à  creuser pour vraiment comprendre ce code, mais je crois bien que j'y suis... j'ose pas le dire trop fort tellement j'ai eu plusieurs fois des faux espoir.  :-* Philippe

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

    CGFloat step=0.5;

    NSMutableArray * array=[NSMutableArray array];

    CGFloat nStep = 0;
    for(nStep=0;currentAngle>step;nStep++,currentAngle-=step){
    NSValue * value= [NSValue valueWithCATransform3D:CATransform3DMakeRotation(currentAngle,0.,0.0,1.0)];
    [array addObject:value];
    }
    [array addObject:[NSValue valueWithCATransform3D:CATransform3DIdentity]];

    CAKeyframeAnimation * transformAnimation=[CAKeyframeAnimation animationWithKeyPath:@transform];
    transformAnimation.values=array;
    transformAnimation.duration=2.0;
    [cadran.layer addAnimation:transformAnimation forKey:nil];
    cadran.transform = CGAffineTransformIdentity;
    }


    J'ai rajouté la dernière ligne pour éviter que le cadran ne revienne en position où il était lâché.
  • Philippe49Philippe49 Membre
    09:29 modifié #20
    Oui nStep=0.5, c'est en gros Pi/6.
    Il reste à  prévoir le cas currentAngle<0 , et à  adapter transformAnimation.duration au nombre de tours à  effectuer, que tu récupères par nStep, ou directement par |currentAngle| (auquel cas nStep est inutile)

    TU peux aussi réaliser en plus un "bounce effect" à  la fin de l'anim en ajoutant quelques values dans la NSArray ...
  • MAGEMAGE Membre
    09:29 modifié #21
    Oui, ben non en fait c'est pas tout à  fait gagné.

    Sur le simulateur, tout va bien. Mais sur le device, j'ai un comportement bizarre avec des mouvements rapides. J'explique :

    - je tourne mon cadran = OK, il suit
    - je lâche = j'ai une image (très rapide) qui affiche le cadran en position de départ, puis il se remet immédiatement en position juste (où je l'ai lâché). Puis l'animation de retour se fait normalement.

    Le résultat est à  peine visible, mais ça perturbe l'animation.

    Je penchais pour un soucis avec cadran.transform = CGAffineTransformIdentity;
    Mais si je ne le mets pas, c'est une fois que toute l'animation est bien faite, que la dernière image saute sur la position où il a été lâché.
  • Philippe49Philippe49 Membre
    09:29 modifié #22
    Je n'ai pas remarqué sur le device, mais si tu le dis ... il faut dire que c'est el layer qui est animé pas la view. Moi j'avais mis
    cadran.layer.transform = CATransform3DIdentity;
  • MAGEMAGE Membre
    09:29 modifié #23
    T'es un magicien 
  • AliGatorAliGator Membre, Modérateur
    09:29 modifié #24
    Ouh là  faut que je garde ce post sous le coude, j'avais le même souci avec une de mes animations ;)

    (j'en parle dans la conclu de mon post ici)
    J'avais pas trouvé la solution (en fait j'avais aussi arrêté de chercher) mais ça va m'inciter à  m'y remettre juste pour voir :D
Connectez-vous ou Inscrivez-vous pour répondre.