Connaà®tre la position d'une vue pendant une animation
En jouant avec UIView.animate() je me suis aperçu d'un truc curieux, il est impossible de connaà®tre la position d'une vue pendant une animation de mouvement.
Pour tester ça, j'ai écrit une mini application déplaçant une barre verticale de droite à gauche.
import UIKit
class Rectangle : UIView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print ("touchesBegan")
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.tag = 1
let sizeEcran = self.view.bounds.size
/*
let vueRouge = UIView(frame: CGRect(x: 0,
y: 0,
width: sizeEcran.width*0.4,
height: sizeEcran.height))
*/
let vueRouge = Rectangle(frame: CGRect(x: 0,
y: 0,
width: sizeEcran.width*0.4,
height: sizeEcran.height))
vueRouge.backgroundColor = UIColor.red
self.view.addSubview(vueRouge)
vueRouge.tag = 42
let pointDestination = CGPoint(x: sizeEcran.width-vueRouge.bounds.width*0.5,
y: sizeEcran.height*0.5)
UIView.animate(withDuration: 2.0,
delay: 0,
options: [.repeat,
.autoreverse,
.curveLinear,
.allowUserInteraction],
animations: { vueRouge.center = pointDestination },
completion: nil)
}
@IBAction func actionTap(_ sender: UITapGestureRecognizer) {
let pos = sender.location(in: self.view)
/*
if let vueDetection = self.view.hitTest(pos, with: nil) {
print ("Tag : ", vueDetection.tag)
}
*/
if let test = detectionVue(vue: self.view, position: pos) {
print ("Tag : ", test.tag)
}
}
func detectionVue(vue:UIView, position:CGPoint) -> UIView? {
for subView in vue.subviews {
if !subView.isHidden {
print ("subview (tag ",subView.tag, ") : ", subView.frame)
}
}
return nil
}
}
Une gesture définie dans le Storyboard appelle la fonction actionTap() quand l'utilisateur touche l'écran.
Normalement les interactions utilisateurs sont désactivés pendant les animations, mais j'ai utilisé le paramètre .allowUserInteraction pour les réactiver. J'ai d'abord utiliser hitTest(), puis j'ai écrit une fonction spécialisée allant lire les subviews de l'écran pour tester individuellement chaque vue. Ensuite j'ai tenté de sous-classer la vue. Le code en haut est un peu bordélique à cause de tous ces essais.
Conclusion : pendant une animation de mouvement, le système considère que la vue est TOUJOURS A SA POSITION FINALE. Quelque soit la position visible de la barre pendant l'animation, pour UIKit elle est à droite de l'écran.
Comme vous pouvez avec les relevés de position suivants, UIKit ne semble pas savoir que la barre se balade sur l'écran, alors que j'ai lu la position à différents moments de l'animation.
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
subview (tag 42 ) : (192.0, 0.0, 128.0, 568.0)
Je ne sais pas comment UIKit se débrouille pour gérer les animations, mais en tout cas il cache bien l'information de position. La vue semble toujours au même endroit, le layer aussi.
Quelqu'un a une suggestion sur la manière de lire la position de l'animation à un moment t ?
Réponses
https://stackoverflow.com/questions/7624755/accessing-the-current-position-of-uiview-during-animation ?
=> view.layer.presentation.frame ?
YEEEEES ça marche !!!
Ceci dit, je ne comprend pas pourquoi view.layer.bounds donne une information (très) différente de view.layer.presentation().frame.
J'ai trouvé ceci :
https://www.invasivecode.com/weblog/interactive-animation-view-ios-10/?doing_wp_cron=1499361002.7799599170684814453125
ça t'intéresse ?
Oui, c'est sacrément intéressant. Y compris la possibilité de définir des trajectoires d'animation avec des courbes complexes. Merci nounours !
Et ceci :
http://jamesonquave.com/blog/designing-animations-with-uiviewpropertyanimator-in-ios-10-and-swift-3/
:-*
Eh bien, je vais avoir de quoi lire ce soir ..
C'est sympa de voir qu'iOS 10 intègre une nouvelle API d'animation (UIViewPropertyAnimator) pour pallier aux limitations de l'ancien système, UIView.animate() apparu avec iOS 4.0, qui commençait à marquer son âge. Il était temps d'avoir un peu de sang neuf.
La nouvelle API a une propriété pour activer le hitTesting. Sympa ..
La doc complète ici : https://developer.apple.com/documentation/uikit/uiviewpropertyanimator
On peut aussi mettre une animation sur pause. Pratique ..
Voici le programme corrigé, avec détection d'une vue avec une animation de mouvement, basé sur la nouvelle API UIViewPropertyAnimator. A la différence que l'animation de la barre rouge n'est pas permanente. Je n'ai pas trouvé le moyen de répéter une animation à l'infini. Le paramètre .repeat de l'ancienne API ne fonctionne pas. L'animation est exécutée 1000 fois, ce qui est suffisant pour les tests.
Le tag 1 est associé à l'écran vide, la valeur 42 à la barre en mouvement !