I need to animate a CATextLayer's bounds.size.height, position, and fontSize. When I add them to a CAAnimationGroup, the text jitters during the animation, just like this:
The jittering of the text's tracking values (spacing between characters) seems to occur while animating fontSize with bounds.size.height AND/OR position. I've isolated fontSize, and it performs well on its own.
How can I prevent the text from jittering in CATextLayer if I animate bounds and font size at the same time?
EDIT
I've moved on from animating bounds. Now, I only care about fontSize + position. Here are two videos showing the difference.
fontSize only (smooth): https://youtu.be/FDPPGF_FzLI
fontSize + position (jittery): https://youtu.be/3rFTsp7wBzk
Here is the code for that.
let startFontSize: CGFloat = 16 let endFontSize: CGFloat = 30 let startPosition: CGPoint = CGPoint(x: 40, y: 100) let endPosition: CGPoint = CGPoint(x: 20, y: 175) // Initialize the layer textLayer = CATextLayer() textLayer.string = "Hello how are you?" textLayer.font = UIFont.systemFont(ofSize: startFontSize, weight: UIFont.Weight.semibold) textLayer.fontSize = startFontSize textLayer.alignmentMode = kCAAlignmentLeft textLayer.foregroundColor = UIColor.black.cgColor textLayer.contentsScale = UIScreen.main.scale textLayer.isWrapped = true textLayer.backgroundColor = UIColor.lightGray.cgColor textLayer.anchorPoint = CGPoint(x: 0, y: 0) textLayer.position = startPosition textLayer.bounds.size = CGSize(width: 450, height: 50) view.layer.addSublayer(textLayer) // Animate let damping: CGFloat = 20 let mass: CGFloat = 1.2 var animations = [CASpringAnimation]() let fontSizeAnim = CASpringAnimation(keyPath: "fontSize") fontSizeAnim.fromValue = startFontSize fontSizeAnim.toValue = endFontSize fontSizeAnim.damping = damping fontSizeAnim.mass = mass fontSizeAnim.duration = fontSizeAnim.settlingDuration animations.append(fontSizeAnim) let positionAnim = CASpringAnimation(keyPath: "position.y") positionAnim.fromValue = textLayer.position.y positionAnim.toValue = endPosition.y positionAnim.damping = damping positionAnim.mass = mass positionAnim.duration = positionAnim.settlingDuration animations.append(positionAnim) let animGroup = CAAnimationGroup() animGroup.animations = animations animGroup.duration = fontSizeAnim.settlingDuration animGroup.isRemovedOnCompletion = true animGroup.autoreverses = true textLayer.add(animGroup, forKey: nil) My device is running iOS 11.0.
EDIT 2
I've broken down each animation (fontSize only, and fontSize + position) frame-by-frame. In each video, I'm progressing 1 frame at a time.
In the fontSize only video (https://youtu.be/DZw2pMjDcl8), each frame yields an increase in fontSize, so there's no choppiness.
In the fontSize + position video (https://youtu.be/_idWte92F38), position is updated in every frame, but not fontSize. There is only an increase in fontSize in 60% of frames, meaning that fontSize isn't animating in sync with position, causing the perceived chopping.
So maybe the right question is: why does fontSize animate in each frame when it's the only animation added to a layer, but not when added as part of CAAnimationGroup in conjunction with the position animation?
1 Answers
Answers 1
Apple DTS believes this issue is a bug. A report has been filed.
In the meantime, I'll be using CADisplayLink to synchronize the redrawing of CATextLayer.fontSize to the refresh rate of the device, which will redraw the layer with the appropriate fontSize in each frame.
0 comments:
Post a Comment