Swift:重复的连续 CABasicAnimations

Posted

技术标签:

【中文标题】Swift:重复的连续 CABasicAnimations【英文标题】:Swift: consecutive CABasicAnimations that repeat 【发布时间】:2019-04-18 01:32:19 【问题描述】:

目标:

第一个动画的持续时间为 1.0 在 1.0 时,第二个动画运行(而第一个动画自动返回到其起点) 在 2.0 中,第一个动画回到起点,第二个动画完成,第一个动画重复 在 3.0 中,第二个动画在第一个动画结束第二次运行时运行

我的代码:

let animation = CABasicAnimation(keyPath: "transform.scale")
        animation.fromValue = 1.0
        animation.toValue = 1.5
        animation.duration = 1.0
        animation.autoreverses = true
        animation.repeatCount = .greatestFiniteMagnitude
        image1.layer.add(animation, forKey: animation.keyPath)

        let animation2 = CABasicAnimation(keyPath: "transform.scale")
        animation2.fromValue = 1.0
        animation2.toValue = 2.0
        animation2.duration = 1.0
        animation2.fillMode = .forwards

        let animation2b = CABasicAnimation(keyPath: "opacity")
        animation2b.fromValue = 1.0
        animation2b.toValue = 0.0
        animation2b.duration = 1.0
        animation2b.fillMode = .forwards

        let animationGroup = CAAnimationGroup()
        animationGroup.animations = [animation2, animation2b]
        animationGroup.duration = 2.0
        animationGroup.beginTime = 1.0
        animationGroup.repeatCount = .greatestFiniteMagnitude
        image2.layer.add(animationGroup, forKey: "scaleAndFade")

目标是在第一个动画之后开始第二个动画 1.0。由于动画组的持续时间为 2.0,而其中的动画持续时间仅为 1.0,因此动画将从 1.0 开始,在 2.0 结束,然后直到 3.0 才再次重复

这两个动画有时会匹配,但不是在每个构建中都匹配。有没有更可靠的方式来启动第二个动画,以在初始动画的第一个完整动画结束时开始?这样他们就会从那时起保持同步。感谢您的帮助!

【问题讨论】:

我建议去掉第一个动画自动反转和重复计数。只需将整个事情描述为单独的动画,然后让小组进行重复。 @matt 如果将第一个动画(使用自动反转,我可以分成 2 个动画)添加到一个图像视图的图层,并且第二组动画(缩放和淡入淡出)在第二个不同的 imageview - 你还会推荐类似的东西吗?每个组都将附加到不同的视图......使用 UIView.animate 及其完成:块会更好吗? 哦,是的,对不起,我明白了,你不能在两个不同的层上做一个组!必须通过完成处理程序链接。可以使用视图或图层来做到这一点。使用递归来获得重复。 【参考方案1】:

我有点不清楚我们想要实现什么,但我的感觉是我们有两个需要协调的重复动画视图。为了演示如何做到这一点的示例,我选择让两个动画都先按比例放大,然后按比例缩小:

这里的 gif 动画在重复几次后就结束了,但实际上重复只是一直持续下去。

简单的实现如下:

func step1() 
    UIView.animate(withDuration: 1, animations: 
        self.v1.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
        self.v2.transform = .identity
    )  _ in
        DispatchQueue.main.async 
            self.step2()
        
    


func step2() 
    UIView.animate(withDuration: 1, animations: 
        self.v1.transform = .identity
        self.v2.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
    )  _ in
        DispatchQueue.main.async 
            self.step1()
        
    

关键是动画的各个阶段永远不会在两个视图之间不同步,因为每个阶段都涉及两个视图并且跟随前一个阶段。所以我很确定你可以调整这种方法来适应你的动画。

【讨论】:

感谢您一直回答并推动我思考我的问题。我经常使用与您在此处显示的这两个函数类似的代码结构。请参阅我的回答,了解我最终针对 CAAnimations 所做的事情。 听起来很棒。我最近有理由自己使用 CATransaction 嵌套,并对它如何解决我遇到的所有问题感到惊讶。 (特别是,我想在 for 循环中触发大量但未知数量的动画,然后在它们 all 完成后运行完成块。)有时达到这个级别是最好的方法。【参考方案2】:

我喜欢@matt 的回答,并且一直很欣赏他们的意见,但由于我尝试使用 CAAnimation(特别是我想使用 CAKeyframeAnimation),我最终使用 CATransaction.begin()CATransaction.setCompletionBlock 嵌套了两个 CATransactions 以准确地开始一个动画其他的结束,然后递归地反复调用函数。

CATransaction documentation

【讨论】:

以上是关于Swift:重复的连续 CABasicAnimations的主要内容,如果未能解决你的问题,请参考以下文章

在Swift中单击按钮而不释放触摸[重复]

swift 删除排序数组中的重复项

Swift,从一个数组中连续播放多个动画?

连续的 UIAlertControllers - IOS - Swift

尝试在 Swift 上触摸屏幕时连续显示一堆图像

使用完成处理程序在 Swift 中调用连续动画