1

我想在特定时间点为 3 个不同的图像设置动画,使其行为如此。

1) 1st image moves from (Xx, Yx) to (Xz,Yz) 
2) Wait 10 seconds
3) 2nd image appears in place at Xa,Yb
4) Wait half as long as in step 2
5) Fade out 2nd image
6) 3rd image appears at the same place as 2nd image

如果这些图像的每个动画都在它们自己的 CALayers 上,我可以使用具有多个图层的 CAKeyframeAnimation 吗?如果没有,还有什么方法可以制作交错动画?

我正在尝试将纸牌从屏幕外移动到特定位置,然后几秒钟后其他一些技巧会出现在屏幕上。

4

2 回答 2

3

已编辑

当我写这篇文章时,我认为你不能使用 CAAnimationGroup 来为多个图层设置动画。马特刚刚发布了一个答案,证明你可以做到这一点。我特此吃掉我的话。

我已将 Matt 的答案中的代码改编为我已上传到Github 的项目(链接。)

Matt 的动画创建的效果是一双脚在屏幕上行走。找了一些开源的foot,安装在项目中,做了一些改动,但是基本的做法是Matt的。给他的道具。

效果如下:

在此处输入图像描述

(下面的说法不正确) 不,您不能使用关键帧动画来制作多个图层的动画。给定的 CAAnimation 只能作用于单个图层。顺便说一下,这包括图层组。

如果你所做的只是在直线上移动图像、淡出和淡入,为什么不使用 UIView 动画呢?看看名称以 animateWithDuration:animations 开头的方法:它们可以让您同时创建多个动画,然后完成块可以触发其他动画。

如果出于某种原因需要使用图层动画,可以使用 beginTime 属性(CAAnimation 对象具有该属性,因为它们符合 CAMediaTiming 协议。)对于不属于动画组的 CAAnimations,您可以使用

animation.beginTime = CACurrentMediaTime() + delay;

其中 delay 是一个 double ,它以秒为单位表示延迟。

如果延迟为 0,则动画将开始。

第三种选择是将您的视图控制器设置为动画的委托,并使用 animationDidStop:finished: 方法链接您的动画。在我看来,这最终是最混乱的实施方法。

于 2013-10-19T22:41:09.120 回答
3

声称单个动画组不能为不同图层的属性设置动画的说法是不正确的。它可以。该技术是将动画组附加到超层,并在各个动画的关键路径中引用子层的属性。

这是一个仅用于演示目的的完整示例。启动时,该项目会显示两个“脚印”,它们交替进行,走出屏幕顶部。

class ViewController: UIViewController, CAAnimationDelegate {

    let leftfoot = CALayer()
    let rightfoot = CALayer()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.leftfoot.name = "left"
        self.leftfoot.contents = UIImage(named:"leftfoot")!.cgImage
        self.leftfoot.frame = CGRect(x: 100, y: 300, width: 50, height: 80)
        self.view.layer.addSublayer(self.leftfoot)

        self.rightfoot.name = "right"
        self.rightfoot.contents = UIImage(named:"rightfoot")!.cgImage
        self.rightfoot.frame = CGRect(x: 170, y: 300, width: 50, height: 80)
        self.view.layer.addSublayer(self.rightfoot)

        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.start()
        }
    }

    func start() {
        let firstLeftStep = CABasicAnimation(keyPath: "sublayers.left.position.y")
        firstLeftStep.byValue = -80
        firstLeftStep.duration = 1
        firstLeftStep.fillMode = .forwards

        func rightStepAfter(_ t: Double) -> CABasicAnimation {
            let rightStep = CABasicAnimation(keyPath: "sublayers.right.position.y")
            rightStep.byValue = -160
            rightStep.beginTime = t
            rightStep.duration = 2
            rightStep.fillMode = .forwards
            return rightStep
        }
        func leftStepAfter(_ t: Double) -> CABasicAnimation {
            let leftStep = CABasicAnimation(keyPath: "sublayers.left.position.y")
            leftStep.byValue = -160
            leftStep.beginTime = t
            leftStep.duration = 2
            leftStep.fillMode = .forwards
            return leftStep
        }

        let group = CAAnimationGroup()
        group.duration = 11
        group.animations = [firstLeftStep]
        for i in stride(from: 1, through: 9, by: 4) {
            group.animations?.append(rightStepAfter(Double(i)))
            group.animations?.append(leftStepAfter(Double(i+2)))
        }
        group.delegate = self
        self.view.layer.add(group, forKey: nil)
    }
    
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        print("done")
        self.rightfoot.removeFromSuperlayer()
        self.leftfoot.removeFromSuperlayer()
    }

}

说了这么多,我应该补充一点,如果您正在为某个核心属性(例如某物的位置)设置动画,则将其设为视图并使用 UIView 关键帧动画来协调不同视图上的动画可能会更简单。不过,关键是说CAAnimationGroup不能做到这一点是错误的。

于 2020-09-02T17:10:05.697 回答