swift - 链接 UIView 动画

问题描述 投票:0回答:2

我想通过以下步骤为我的

UIImageView
制作动画:

  1. 缩放2倍
  2. 缩放图像移动

所以我正在尝试这样:

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 个自定义点,然后放大到初始尺寸。

swift core-animation calayer uiviewanimation
2个回答
7
投票

有几种方法:

  1. 一种方法是将动画的开始放入前一个动画的完成处理程序中:

    UIView.animate(withDuration: 1) { 
        …
    } completion: { _ in
        UIView.animate(withDuration: 2) { 
            …
        } completion: {  _ in 
            UIView.animate(withDuration: 1) { 
                …
            } completion: {  _ in 
                …
            }
        }
    }
    
  2. 如果您想避免嵌套动画塔(每个动画都在前一个动画的完成处理程序中),您可以使用关键帧动画,例如这是一个五秒的动画,具有三个独立的关键帧,每个关键帧的持续时间为总持续时间的三分之一,并且相应地设置其开始时间:

    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 及更高版本。对于早期版本,请参阅此答案的以前的修订版

  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)) {
        …
    }
    

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

© www.soinside.com 2019 - 2024. All rights reserved.