Choppy CATextLayer动画:同时使用fontSize +位置

时间:2017-10-12 03:18:35

标签: ios swift core-animation

我需要为CATextLayer bounds.size.heightpositionfontSize制作动画。当我将它们添加到CAAnimationGroup时,文本会在动画期间抖动,就像这样:

https://youtu.be/HfC1ZX-pbyM

在使用fontSize和/或bounds.size.height设置position动画时,似乎会出现文本跟踪值(字符间距)的抖动。我已经孤立fontSize,并且它自身表现良好。

如果我同时为边界和字体大小设置动画,如何防止文本在CATextLayer中抖动?

修改

我已经开始动画bounds了。现在,我只关心fontSize + position。以下是两个显示差异的视频。

fontSize(流畅):https://youtu.be/FDPPGF_FzLI

fontSize + position(紧张):https://youtu.be/3rFTsp7wBzk

这是代码。

    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)

我的设备正在运行iOS 11.0。

编辑2

我已逐帧细分了每个动画(仅限fontSizefontSize + position)。在每个视频中,我一次进行1帧。

在仅fontSize视频(https://youtu.be/DZw2pMjDcl8)中,每一帧会使fontSize增加,因此不会出现波动。

fontSize + position视频(https://youtu.be/_idWte92F38)中, position会在每一帧中更新,但不会更新fontSize 。 60%的帧中只有fontSize有所增加,这意味着fontSize不会与position同步动画,从而导致感知斩波。

所以也许正确的问题是:为什么fontSize在每一帧中设置动画,因为它是添加到图层的唯一动画,而不是作为CAAnimationGroup的一部分与...一起添加时position动画?

1 个答案:

答案 0 :(得分:6)

Apple DTS认为此问题是一个错误。报告已经提交。

与此同时,我将使用CADisplayLinkCATextLayer.fontSize的重绘同步到设备的刷新率,这将使用适当的fontSize重新绘制图层在每一帧中。

修改

在修补CADisplayLink一天左右之后,绘制到正确的fontSize证明是困难的,尤其是在与自定义计时功能配对时。所以,我完全放弃CATextLayer并回到UILabel

在WWDC' 17' Advanced Animations with UIKit中,Apple建议"查看变形"在两个标签状态之间设置动画 - 即两个视图的平移,缩放和不透明度混合。 UIViewPropertyAnimator为此提供了很多灵活性,例如混合多个计时功能和擦洗。视图变形对于在2个text值之间转换而非必须淡出文本表示,更改text和淡入淡出也很有用。

我希望Apple可以加强CATextLayer对非交互式动画的支持,因为我更喜欢使用一个视图来动画相同的文本表示。