I am using the ideal solution to animate text changes to my UILabel. Similar to this answer https://stackoverflow.com/a/33705634/8704900
The problem is when the texts are not of same length, the animation is no more smooth and the text flickers before animating up.
Video: https://drive.google.com/file/d/1I89NnzjQp7TbemO-dmcbKzYUr7pM7mGk/view?usp=sharing
My code looks like this:
@IBOutlet weak var label: UILabel!
var titleLabelAnimation: CATransition = {
let animation = CATransition()
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.default)
animation.type = .push
animation.subtype = .fromTop
animation.duration = 0.5
return animation
}()
@IBAction func didTap() {
self.label.layer.add(self.titleLabelAnimation, forKey: nil)
self.label.text = "Can you see a flicker?"
self.label.sizeToFit()
}
@IBAction func didTapRev() {
self.label.layer.add(self.titleLabelAnimation, forKey: nil)
self.label.text = "Hello this is animation !!!"
self.label.sizeToFit()
}
I have tried layoutIfNeeded(), sizeToFit(), changing the text before animation and couple of other workarounds. Nothing seem to be working!
Not sure exactly what is going on in your example as I could not produce this result. But animations are in many cases a pain and a lot of things may produce jumping views.
By having a bit more control over animation you might have better luck finding out the issue or fixing it. For your specific case it might already be enough to do your animation using snapshots. Check out the following:
@IBOutlet weak var label: UILabel!
private func animateAsCustom(applyChanges: @escaping (() -> Void)) {
guard let viewToMove = label else { return }
guard let panel = viewToMove.superview else { return }
guard let snapshotView = viewToMove.snapshotView(afterScreenUpdates: true) else { return }
applyChanges()
UIView.performWithoutAnimation {
panel.addSubview(snapshotView)
snapshotView.center = viewToMove.center
viewToMove.transform = CGAffineTransform(translationX: 0.0, y: 50.0) // TODO: compute values for translation
viewToMove.alpha = 0.0
}
UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseIn) {
viewToMove.transform = .identity
snapshotView.transform = CGAffineTransform(translationX: 0.0, y: -50.0)
snapshotView.alpha = 0.0
viewToMove.alpha = 1.0
} completion: { _ in
snapshotView.removeFromSuperview()
}
}
@IBAction func didTap() {
animateAsCustom {
self.label.numberOfLines = 1
self.label.text = "Can you see a flicker?"
self.label.textColor = .red
self.label.font = UIFont.systemFont(ofSize: 20)
}
}
@IBAction func didTapRev() {
animateAsCustom {
self.label.numberOfLines = 0
self.label.text = "Hello this\nis animation !!!"
self.label.textColor = .black
self.label.font = UIFont.systemFont(ofSize: 30)
}
}
This will still not fix the issue if you press one of the buttons before previous animation did finish. To fix that one as well some extra effort may be needed. But for now this solution could be enough.