我拼命想把 asmallLabel
变成 a bigLabel
。通过morphing,我的意思是从一个标签转换以下属性以匹配另一个标签的相应属性,并具有平滑的动画:
- 字体大小
- 字体粗细
- 框架(即边界和位置)
所需的效果应该类似于使用大标题时应用于导航控制器标题标签的动画:
现在我知道去年的 WWDC 会议Advanced Animations with UIKit在那里他们展示了如何做到这一点。但是,这种技术非常有限,因为它基本上只是对标签的框架应用变换,因此它只有在除字体大小之外的所有属性都相同的情况下才有效。
当一个标签有regular
字体粗细而另一个标签有粗细时,该技术已经失败bold
了——这些属性在应用变换时不会改变。因此,我决定深入挖掘并使用 Core Animation 进行变形。
首先,我创建了一个新的文本图层,我将其设置为与以下内容在视觉上相同smallLabel
:
/// Creates a text layer with its text and properties copied from the label.
func createTextLayer(from label: UILabel) -> CATextLayer {
let textLayer = CATextLayer()
textLayer.frame = label.frame
textLayer.string = label.text
textLayer.opacity = 0.3
textLayer.fontSize = label.font.pointSize
textLayer.foregroundColor = UIColor.red.cgColor
textLayer.backgroundColor = UIColor.cyan.cgColor
view.layer.addSublayer(textLayer)
return textLayer
}
然后,我创建必要的动画并将它们添加到该层:
func animate(from smallLabel: UILabel, to bigLabel: UILabel) {
let textLayer = createTextLayer(from: smallLabel)
view.layer.addSublayer(textLayer)
let group = CAAnimationGroup()
group.duration = 4
group.repeatCount = .infinity
// Animate font size
let fontSizeAnimation = CABasicAnimation(keyPath: "fontSize")
fontSizeAnimation.toValue = bigLabel.font.pointSize
// Animate font (weight)
let fontAnimation = CABasicAnimation(keyPath: "font")
fontAnimation.toValue = CGFont(bigLabel.font.fontName as CFString)
// Animate bounds
let boundsAnimation = CABasicAnimation(keyPath: "bounds")
boundsAnimation.toValue = bigLabel.bounds
// Animate position
let positionAnimation = CABasicAnimation(keyPath: "position")
positionAnimation.toValue = bigLabel.layer.position
group.animations = [
fontSizeAnimation,
boundsAnimation,
positionAnimation,
fontAnimation
]
textLayer.add(group, forKey: "group")
}
这是我得到的:
如您所见,它并没有按预期工作。这个动画有两个问题:
字体粗细不会动画,但会在动画过程中突然切换。
当(青色)文本图层的框架按预期移动并增大大小时,文本本身以某种方式向图层的左下角移动并从右侧被切断。
我的问题是:
1️⃣为什么会发生这种情况(尤其是2.)?
和