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