首页 > 解决方案 > 为什么我不能为作为 CAAnimationGroup 一部分的图层子图层的路径设置动画,但我可以为组中的其他属性设置动画?

问题描述

感谢@matt,我不久前了解到可以在CAAnimationGroup. 诀窍是为子层添加名称。

有关该技术的讨论,请参见 Matt 在此线程中的回答,以及我为测试它而编写的一个工作示例。

然后将动画组添加到父层,并在影响父层的子层的动画中,使用keyPath将子层引用为父层的命名子层的值创建这些子层动画。

所以如果我有 CAShapeLayer parentLayer,那也有一个名为“sublayer”的子层,

let parentLayer = CAShapeLayer()
let sublayer = CAShapeLayer()
sublayer.name = "sublayer"
parentLayer.addSublayer(sublayer)

我想创建一个动画组,同时为父层和子层的属性设置动画,该代码可能如下所示:

let animationGroup = CAAnimationGroup()
animationGroup.duration = animationDuration

let parentLayerAnimation = CABasicAnimation(keyPath: "path")
parentLayerAnimation.duration = animationDuration
parentLayerAnimation.fromValue = parentLayer.path
parentLayerAnimation.toValue = newPath

let sublayerAnimation = CABasicAnimation(keyPath: "sublayers.sublayer.path")
sublayerAnimation.duration = animationDuration
sublayerAnimation.fromValue = subLayer.path
sublayerAnimation.toValue = newSublayerPath

let animationGroup = CAAnimationGroup()
animationGroup.duration = animationDuration
animationGroup.animations = [parentLayerAnimation, sublayerAnimation]
parentLayer.add(animationGroup, forKey: nil)

上面的代码不起作用。问题似乎特别在于尝试为子图层的路径设置动画。如果我改为动画子层的旋转,使用如下代码:

let sublayerRotationAnimation = CABasicAnimation(keyPath: "sublayers.sublayer.transform.rotation.z")
sublayerRotationAnimation.duration = animationDuration
sublayerRotationAnimation.fromValue = 0
sublayerRotationAnimation.toValue = CGFloat.pi

并将其添加sublayerRotationAnimation到动画组中,这样就可以了。

如果我尝试为子图层的路径设置动画,似乎会出现问题。动画其他属性的作品。

(如果我将子图层动画的关键路径更改为“路径”并将动画直接添加到子图层,那也可以。)

我追求的效果是这样的:

在此处输入图像描述

(动画成弧线的黑色插入符号是父层,带点的红线是子层bezierIllustrationLayer。)

我在 Github 上有一个工作项目的一个分支,它说明了这个问题:

带有动画组的 Github 项目分支不起作用

项目的主要分支只是将单独的动画提交给图层和子图层,并且可以正常工作。

该分支中尝试添加动画组的代码位于文件 CaretToArcView.swift 中:

let pathAnimation = CABasicAnimation(keyPath: "path")
pathAnimation.duration = animationDuration
pathAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
pathAnimation.fromValue = layer.path
pathAnimation.toValue = path.cgPath

// This animation does not work when added to an animation group applied to the parent layer of the bezierIllustrationLayer
let bezierPathAnimation = CABasicAnimation(keyPath: "sublayers.bezierillustrationlayer.path")
bezierPathAnimation.duration = animationDuration
bezierPathAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
bezierPathAnimation.fromValue = bezierIllustrationLayer.path
bezierPathAnimation.toValue = illustrationPath.cgPath

//If I add this rotation animation to the animation group, it works
//let rotationAnimation = CABasicAnimation(keyPath: "sublayers.bezierillustrationlayer.transform.rotation.z")
//rotationAnimation.duration = 1.0
//rotationAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
//rotationAnimation.fromValue = 0
//rotationAnimation.toValue  = CGFloat.pi * 2

let animationGroup = CAAnimationGroup()
animationGroup.duration = animationDuration
animationGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
animationGroup.animations = [pathAnimation, bezierPathAnimation]
layer.add(animationGroup, forKey: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    layer.path = path.cgPath
    self.bezierIllustrationLayer.path = illustrationPath.cgPath
}

据我所知,这是 CAAnimationGroup 中的一个错误。如果我将它直接应用于子层(在适当地更改 keyPath 之后),则相同的动画可以工作。不同属性的动画,如动画组中子图层的transform.rotation.z作品。它只是为失败的子层路径设置动画。

有没有其他人遇到过这种情况,您有解决方案吗?马特? 我认为你是这里的 CAAnimation 专家。你能帮我吗?

标签: iosswiftcore-animationcashapelayercaanimation

解决方案


推荐阅读