Echelle CGAffineTransform et traduction – saut avant animation

Je suis aux sockets avec un problème concernant l'échelle et la traduction de CGAffineTransform: lorsque je place une transformation dans un bloc d'animation sur une vue qui a déjà une transformation, la vue saute un peu avant d'être animée.

Exemple:

// somewhere in view did load or during initialization var view = UIView() view.frame = CGRectMake(0,0,100,100) var scale = CGAffineTransformMakeScale(0.8,0.8) var translation = CGAffineTransformMakeTranslation(100,100) var concat = CGAffineTransformConcat(translation, scale) view.transform = transform // called sometime later func buttonPressed() { var secondScale = CGAffineTransformMakeScale(0.6,0.6) var secondTranslation = CGAffineTransformMakeTranslation(150,300) var secondConcat = CGAffineTransformConcat(secondTranslation, secondScale) UIView.animateWithDuration(0.5, animations: { () -> Void in view.transform = secondConcat }) } 

Maintenant, lorsque buttonPressed () est appelé, la vue saute en haut à gauche d'environ 10 pixels avant de commencer à animer. J'ai seulement été témoin de ce problème avec une transformation de concat, en utilisant seulement une transformation de traduction fonctionne très bien.

Edit: Depuis que j'ai fait beaucoup de searchs sur le sujet, je pense que je devrais mentionner que ce problème apparaît indépendamment du fait que la layout automatique soit activée ou non

J'ai rencontré le même problème, mais je n'ai pas trouvé la source exacte du problème. Le saut ne semble apparaître que dans des conditions très spécifiques: Si la vue s'anime d'une transformation t1 vers une transformée t2 et que les deux transformations sont une combinaison d'une échelle et d'une traduction (c'est exactement votre cas). Compte tenu de la solution de contournement suivante, ce qui n'a pas de sens pour moi, je suppose que c'est un bug dans Core Animation.

J'ai d'abord essayé d'utiliser CATransform3D au lieu de CGAffineTransform .

Ancien code:

 var transform = CGAffineTransformIdentity transform = CGAffineTransformScale(transform, 1.1, 1.1) transform = CGAffineTransformTranslate(transform, 10, 10) view.layer.setAffineTransform(transform) 

Nouveau code:

 var transform = CATransform3DIdentity transform = CATransform3DScale(transform, 1.1, 1.1, 1.0) transform = CATransform3DTranslate(transform, 10, 10, 0) view.layer.transform = transform 

Le nouveau code devrait être équivalent à l'ancien (le quasortingème paramètre est mis à 1.0 ou 0 sorte qu'il n'y ait pas de mise à l'échelle / translation dans la direction z ), et en fait il montre le même saut. Cependant, voici la magie noire: Dans la transformation d'échelle, changez le paramètre z en quelque chose de différent de 1.0 , comme ceci:

 transform = CATransform3DScale(transform, 1.1, 1.1, 1.01) 

Ce paramètre ne devrait avoir aucun effet, mais maintenant le saut est parti.

🎩✨

La source du problème est le manque d'informations sur la perspective de la transformation.

Vous pouvez append des informations de perspective modifiant la propriété m34 de votre transformation 3D

 var transform = CATransform3DIdentity transform.m34 = 1.0 / 200 //your own perspective value here transform = CATransform3DScale(transform, 1.1, 1.1, 1.0) transform = CATransform3DTranslate(transform, 10, 10, 0) view.layer.transform = transform 

On dirait un bug interne de l'animation Apple UIView. Lorsque Apple interpole les modifications CGAffineTransform entre deux valeurs pour créer une animation, elle doit effectuer les étapes suivantes:

  • Extraction de la traduction, de l'échelle et de la rotation
  • Interpoler les valeurs extraites du début à la fin
  • Assemblez CGAffineTransform pour chaque étape d'interpolation

L'assemblage doit être dans l'ordre suivant:

  • Traduction
  • Mise à l'échelle
  • Rotation

Mais on dirait qu'Apple fait la traduction après la mise à l'échelle et la rotation. Ce bug devrait être corrigé par Apple.

Au lieu de CGAffineTransformMakeScale () et CGAffineTransformMakeTranslation (), qui créent une transformation basée sur CGAffineTransformIdentity (essentiellement pas de transformation), vous souhaitez resize et traduire en fonction de la transformation actuelle de la vue à l'aide de CGAffineTransformScale () et CGAffineTransformTranslate (). transformer.