【问题标题】:How to sequence two animations with delay in between如何对两个动画之间有延迟进行排序
【发布时间】:2018-02-11 18:46:12
【问题描述】:

我有一个UIImageView,我想旋转 180 度,占用 1 秒,然后我想在这个位置等待 1 秒,然后旋转 180 度回到原来的位置,占用 1 秒。

我如何做到这一点?我已经尝试了 100 种方法,但它一直在回弹而不是回旋

编辑:我忘了补充我需要这个无限期地重复

【问题讨论】:

  • 在问题中添加您尝试过的代码

标签: ios swift core-animation


【解决方案1】:

您需要做的就是创建一个keyFrame animations。它旨在将多个动画链接在一起,并在第一个关键帧中将您的 UIImageView 子类旋转 PI,然后在第二个关键帧中将其转换回 identity

        let rotateForwardAnimationDuration: TimeInterval = 1
        let rotateBackAnimationDuration: TimeInterval = 1
        let animationDuration: TimeInterval = rotateForwardAnimationDuration + rotateBackAnimationDuration

        UIView.animateKeyframes(withDuration: animationDuration, delay: 0, options: [], animations: { 
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: rotateForwardAnimationDuration) {
                self.imageView.transform = CGAffineTransform(rotationAngle: .pi)
            }

            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: rotateBackAnimationDuration) { 
                self.imageView.transform = .identity 
            }
        })

结果:

编辑: 这是一个如何使其无限期运行的示例。我想您的图像在 viewController 中,并且您持有对 imageView 的一些引用。

例如,在viewDidAppear,调用触发动画的函数,然后在动画的完成块中,再次调用相同的函数。

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.runRotateAnimation()
    }

    func runRotateAnimation() {
        let rotateForwardAnimationDuration: TimeInterval = 1
        let rotateBackAnimationDuration: TimeInterval = 1
        let animationDuration: TimeInterval = rotateForwardAnimationDuration + rotateBackAnimationDuration

        UIView.animateKeyframes(withDuration: animationDuration, delay: 0, options: [], animations: { 
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: rotateForwardAnimationDuration) {
                self.imageView.transform = CGAffineTransform(rotationAngle: .pi)
            }

            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: rotateBackAnimationDuration) { 
                self.imageView.transform = .identity 
            }
        }) { (isFinished) in
            // To loop it continuosly, just call the same function from the completion block of the keyframe animation
            self.runRotateAnimation()
        }
    }
}

【讨论】:

  • 感谢您的回复!这有效1次,如果我需要它重复怎么办?我已经更新了我的问题
  • 谢谢!看起来这会随着时间的推移对堆栈造成相当大的污染,这无关紧要吗?
  • pollute the stack 是什么意思?无论您做什么,每个递归函数都会污染堆栈。如果您关心性能,请查看CABasicAnimation,什么是支持repeatCount 属性的更轻量级的动画。
  • 是的,每个递归函数都会填满堆栈,但是这个永远连续,通常不希望这样。如果您有多个以短延迟运行,则它可能会填满堆栈。我将尝试将其转换为循环。谢谢!
  • 这没什么区别,像这样永远运行动画会导致性能问题。就像我提到的那样,您需要一种不同的方法。
【解决方案2】:

您可以在 UIView.animate 上呈现的 completionHandler 中执行第二个动画

let duration = self.transitionDuration(using: transitionContext)

let firstAnimDuration = 0.5
UIView.animate(withDuration: firstAnimDuration, animations: {
    /* Do here the first animation */
}) { (completed) in

   let secondAnimDuration = 0.5
   UIView.animate(withDuration: secondAnimDuration, animations: { 
       /* Do here the second animation */
   })
}

现在你可能会遇到另一个问题。

如果您使用 CGAffineTransform 旋转您的视图,并且为每个动画分配一个此类型的新对象到您的 view.transform,您将丢失之前的变换操作

所以,根据这个帖子:How to apply multiple transforms in Swift,你需要concat变换操作

以 2 个动画块为例

这是一个旋转 180 度并在 1 秒后返回原点的示例:

let view = UIView.init(frame: CGRect.init(origin: self.view.center, size: CGSize.init(width: 100, height: 100)))
view.backgroundColor = UIColor.red
self.view.addSubview(view)

var transform = view.transform
transform = transform.rotated(by: 180)

UIView.animate(withDuration: 2, animations: {
    view.transform = transform
}) { (completed) in

    transform = CGAffineTransform.identity
    UIView.animate(withDuration: 2, delay: 1, options: [], animations: { 
        view.transform = transform
    }, completion: nil)
}

.repeat 动画和 .autoreverse 示例

.animate 方法使您能够设置一些动画选项。特别是 UIViewAnimationOptions 包含的结构:

  1. .repeat,无限重复你的动画块
  2. .autoreverse,将您的视图恢复到原始状态

考虑到这一点,您可以这样做:

var transform = view.transform.rotated(by: 180)
UIView.animate(withDuration: 2, delay: 0, options: [.repeat, .autoreverse], animations: {
     self.myView.transform = transform
})

但是你需要两个动画之间有一个延迟,所以你需要做这个技巧:

递归动画示例和延迟 1 秒

只需在您的 ViewController 中创建一个方法来为您的视图设置动画。在最后一个completionHandler中,只需调用该方法创建一个无限循环。

最后你需要调用 viewDidAppear 上的方法来启动动画。

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    self.animation()
}


func animation() {
    var transform = view.transform
    transform = transform.rotated(by: 180)

    UIView.animate(withDuration: 2, delay: 0, options: [], animations: {

        self.myView.transform = transform

    }) { bool in
        transform = CGAffineTransform.identity

        UIView.animate(withDuration: 2, delay: 1, options: [], animations: {

            self.myView.transform = transform

        }, completion: { bool in
            self.animation()
        })
    }
}

【讨论】:

  • 感谢您的回复!这工作 1 次,如果我需要它重复呢?我已经更新了我的问题
  • 很好,但不会因为递归而导致内存过载,只是好奇吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多