我想通过以下步骤为我的
UIImageView
制作动画:
所以我正在尝试这样:
UIView.animate(withDuration: 0.5, animations: {
self.imageView.transform = CGAffineTransform(scaleX: 2, y: 2)
}) { _ in
UIView.animate(withDuration: 1.0, animations: {
self.imageView.transform = CGAffineTransform(translationX: -50, y: -50)
}) { _ in
//other steps
}
}
但是结果是在移动之前
imageView
又恢复到之前的大小然后再移动。如何移动缩放view
?
我也尝试过更改
anchorPoint
块内图层的 animate
,但没有成功
也许有更简单的方法来实现我的目标:能够缩小图像,然后聚焦在 3 个自定义点,然后放大到初始尺寸。
有几种方法:
一种方法是将动画的开始放入前一个动画的完成处理程序中:
UIView.animate(withDuration: 1) {
…
} completion: { _ in
UIView.animate(withDuration: 2) {
…
} completion: { _ in
UIView.animate(withDuration: 1) {
…
} completion: { _ in
…
}
}
}
如果您想避免嵌套动画塔(每个动画都在前一个动画的完成处理程序中),您可以使用关键帧动画,例如这是一个五秒的动画,具有三个独立的关键帧,每个关键帧的持续时间为总持续时间的三分之一,并且相应地设置其开始时间:
UIView.animateKeyframes(withDuration: 5, delay: 0) {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1 / 3) {
…
}
UIView.addKeyframe(withRelativeStartTime: 1 / 3, relativeDuration: 1 / 3) {
…
}
UIView.addKeyframe(withRelativeStartTime: 2 / 3, relativeDuration: 1 / 3) {
…
}
}
以上适用于 Swift 5.3 及更高版本。对于早期版本,请参阅此答案的以前的修订版。
如今,我们可能会自然而然地寻求 Swift 并发性(因为它擅长管理异步任务之间的依赖关系),而且一般来说,Swift 非常擅长渲染
async
带有完成处理程序参数的旧 Objective-C API 的再现(请参阅 SE- 0297:与 Objective-C 的并发互操作性:异步完成处理程序方法)。但是 UIView
动画函数(尚未)优雅地映射到 async
再现。因此,我们可以使用延续来编写我们自己的 async
动画 API 的 UIView
再现:
extension UIView {
class func animate(
for duration: Duration,
delay: Duration = .zero,
options: UIView.AnimationOptions = [],
animations: @MainActor @Sendable @escaping () -> Void
) async {
await withCheckedContinuation { continuation in
UIView.animate(
withDuration: duration.timeInterval,
delay: delay.timeInterval,
options: options,
animations: animations
) { _ in
continuation.resume()
}
}
}
}
extension Duration {
var timeInterval: TimeInterval {
let (wholeSeconds, attoseconds) = components
return TimeInterval(wholeSeconds) + TimeInterval(attoseconds) / 1e18
}
}
然后,从异步上下文中,您可以使用 Swift 并发:
await UIView.animate(for: .seconds(1), delay: .seconds(1.5)) {
…
}
await UIView.animate(for: .seconds(1)) {
…
}
await UIView.animate(for: .seconds(1)) {
…
}
对于第一个问题:由于您将
transform
分配给新的而不保留旧的配置,因此在第二个动画中,您的视图将转换为默认比例 (1, 1)。您所需要做的只是将 transform
分配给一个新配置,其中包含所有旧配置以及您想要的新配置。
UIView.animate(withDuration: 0.5, animations: {
self.button.transform = self.button.transform.scaledBy(x: 2, y: 2)
}) { _ in
UIView.animate(withDuration: 1.0, animations: {
self.button.transform = self.button.transform.translatedBy(x: -50, y: -50)
}) { _ in
}
}
如果使用就更好了
animateKeyframes