【问题标题】:Unexpected behaviour in animation when i change the properties of the model layers当我更改模型层的属性时动画中的意外行为
【发布时间】:2023-09-25 05:37:01
【问题描述】:

参考this 帖子,我正在尝试将动画调整为横向模式。基本上我想要的是旋转-90°(顺时针90°)的所有图层,并且动画水平运行而不是垂直运行。作者没有费心解释背后的逻辑,obj-c 中有十几个纸折叠库,它们都是基于相同的架构,所以显然这是折叠的方式。

编辑:为了进一步阐明我想要实现的目标,here 你可以查看我想要的动画的三个快照(起点、半场和终点)。在上面链接的问题中,动画从下到上折叠,而我希望它从左到右折叠。

您可以在下面查看原始项目,稍作调整:

  • 我改变了灰色bottomSleeve层的最终角度值,以及红色和蓝色的角度;
  • 我通过设置perspectiveLayer speed 等于0 来暂停动画初始化并添加一个滑块,然后将滑块值设置为等于perspectiveLayer timeOffset 以便您可以交互地运行每个通过滑动动画帧。当滑块上的触摸事件结束时,动画会从相对于当前timeOffset 的帧恢复到最终值。
  • 在运行每个使用CATransaction 添加到相关表示层的动画之前,我更改了所有模型层的值。此外,在完成时,perspectiveLayer 速度再次设置为 0
  • 为了更好的视觉理解,我将perspectiveLayer backgroundColor 设置为等于cyan

只是指出,有两个主要功能:

  1. setupLayers(),在viewDidLoad() 中调用,负责设置图层位置和锚点,并将它们作为子图层添加到mainView 图层。
  2. animate(),在setupLayers()中递归调用,负责添加动画。在这里,我还将模型层的值设置为相关动画的最终值,然后再添加它们。

只需复制、粘贴并运行:

class ViewController: UIViewController {

var transform: CATransform3D = CATransform3DIdentity
var topSleeve: CALayer = CALayer()
var middleSleeve: CALayer = CALayer()
var bottomSleeve: CALayer = CALayer()
var topShadow: CALayer = CALayer()
var middleShadow: CALayer = CALayer()
let width: CGFloat = 300
let height: CGFloat = 150
var firstJointLayer: CATransformLayer = CATransformLayer()
var secondJointLayer:CATransformLayer = CATransformLayer()
var sizeHeight: CGFloat = 0
var positionY: CGFloat = 0

var perspectiveLayer: CALayer = {
    let perspectiveLayer = CALayer()
    perspectiveLayer.speed = 0.0
    perspectiveLayer.fillMode = .removed
    return perspectiveLayer
}()

var mainView: UIView = {
    let view = UIView()
    return view
}()

private let slider: UISlider = {
    let slider = UISlider()
    slider.addTarget(self, action: #selector(slide(sender:event:)) , for: .valueChanged)
    return slider
}()

override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(slider)
    setupLayers()
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    slider.frame = CGRect(x: view.bounds.size.width/3,
                          y: view.bounds.size.height/10*8,
                          width: view.bounds.size.width/3,
                          height: view.bounds.size.height/10)
}

@objc private func slide(sender: UISlider, event: UIEvent) {
    if let touchEvent = event.allTouches?.first {
        
        switch touchEvent.phase {
        case .ended:
            resumeLayer(layer: perspectiveLayer)
        default:
            perspectiveLayer.timeOffset = CFTimeInterval(sender.value)
        }
        
    }
}

private func resumeLayer(layer: CALayer) {
    let pausedTime = layer.timeOffset
    layer.speed = 1.0
    layer.timeOffset = 0.0
    layer.beginTime = 0.0
    let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
    layer.beginTime = timeSincePause
}

private func setupLayers() {
    
    mainView = UIView(frame:CGRect(x: 50, y: 50, width: width, height: height*3))
    mainView.backgroundColor = UIColor.yellow
    view.addSubview(mainView)
    
    perspectiveLayer.frame = CGRect(x: 0, y: 0, width: width, height: height*2)
    perspectiveLayer.backgroundColor = UIColor.cyan.cgColor
    mainView.layer.addSublayer(perspectiveLayer)
    
    firstJointLayer.fillMode = .removed
    firstJointLayer.frame = mainView.bounds
    perspectiveLayer.addSublayer(firstJointLayer)
    
    topSleeve.fillMode = .removed
    topSleeve.frame = CGRect(x: 0, y: 0, width: width, height: height)
    topSleeve.anchorPoint = CGPoint(x: 0.5, y: 0)
    topSleeve.backgroundColor = UIColor.red.cgColor
    topSleeve.position = CGPoint(x: width/2, y: 0)
    firstJointLayer.addSublayer(topSleeve)
    topSleeve.masksToBounds = true
    
    secondJointLayer.fillMode = .removed
    secondJointLayer.frame = mainView.bounds
    secondJointLayer.frame = CGRect(x: 0, y: 0, width: width, height: height*2)
    secondJointLayer.anchorPoint = CGPoint(x: 0.5, y: 0)
    secondJointLayer.position = CGPoint(x: width/2, y: height)
    firstJointLayer.addSublayer(secondJointLayer)
    
    secondJointLayer.fillMode = .removed
    middleSleeve.frame = CGRect(x: 0, y: 0, width: width, height: height)
    middleSleeve.anchorPoint = CGPoint(x: 0.5, y: 0)
    middleSleeve.backgroundColor = UIColor.blue.cgColor
    middleSleeve.position = CGPoint(x: width/2, y: 0)
    secondJointLayer.addSublayer(middleSleeve)
    middleSleeve.masksToBounds = true
    
    bottomSleeve.fillMode = .removed
    bottomSleeve.frame = CGRect(x: 0, y: height, width: width, height: height)
    bottomSleeve.anchorPoint = CGPoint(x: 0.5, y: 0)
    bottomSleeve.backgroundColor = UIColor.gray.cgColor
    bottomSleeve.position = CGPoint(x: width/2, y: height)
    secondJointLayer.addSublayer(bottomSleeve)
    
    firstJointLayer.anchorPoint = CGPoint(x: 0.5, y: 0)
    firstJointLayer.position = CGPoint(x: width/2, y: 0)
    
    topShadow.fillMode = .removed
    topSleeve.addSublayer(topShadow)
    topShadow.frame = topSleeve.bounds
    topShadow.backgroundColor = UIColor.black.cgColor
    topShadow.opacity = 0
    
    middleShadow.fillMode = .removed
    middleSleeve.addSublayer(middleShadow)
    middleShadow.frame = middleSleeve.bounds
    middleShadow.backgroundColor = UIColor.black.cgColor
    middleShadow.opacity = 0
    
    transform.m34 = -1/700
    perspectiveLayer.sublayerTransform = transform
    
    sizeHeight = perspectiveLayer.bounds.size.height
    positionY = perspectiveLayer.position.y
    
    animate()
}


private func animate() {
    
    CATransaction.begin()
    
    CATransaction.setDisableActions(true)
    
    CATransaction.setCompletionBlock{ [weak self] in
        if self == nil { return }
        self?.perspectiveLayer.speed = 0
    }
    
    firstJointLayer.transform = CATransform3DMakeRotation(CGFloat(-85*Double.pi/180), 1, 0, 0)
    secondJointLayer.transform = CATransform3DMakeRotation(CGFloat(170*Double.pi/180), 1, 0, 0)
    bottomSleeve.transform = CATransform3DMakeRotation(CGFloat(-165*Double.pi/180), 1, 0, 0)
    perspectiveLayer.bounds.size.height = 0
    perspectiveLayer.position.y = 0
    topShadow.opacity = 0.5
    middleShadow.opacity = 0.5
    
    var animation = CABasicAnimation(keyPath: "transform.rotation.x")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = -85*Double.pi/180
    firstJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "transform.rotation.x")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 170*Double.pi/180
    secondJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "transform.rotation.x")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = -165*Double.pi/180
    bottomSleeve.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "bounds.size.height")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = sizeHeight
    animation.toValue = 0
    perspectiveLayer.add(animation, forKey: nil)
    
    
    animation = CABasicAnimation(keyPath: "position.y")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = positionY
    animation.toValue = 0
    perspectiveLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "opacity")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 0.5
    topShadow.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "opacity")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 0.5
    middleShadow.add(animation, forKey: nil)
    CATransaction.commit()

}
}

正如您所见,动画按预期运行,此时要旋转整个物体,只需更改位置、锚点和最终动画值即可。 摘自上面链接的答案,这里是起始项目所有层的一个很好的表示:

然后我继续重构 setupLayers()animate() 以从左到右水平运行动画(换句话说,我在上面的图层表示中顺时针旋转 90°)。

更改代码以旋转动画后,我遇到了两个问题:

  1. 当动画开始时,firstJointLayer 位置沿perspectiveLayer 从左向右平移。公平地说,这应该是一种预期的行为,因为它是perspectiveLayer 的子层,实际上我不确定为什么在原始项目中它不会发生。但是,为了解决这个问题,我添加了另一个动画,负责在其相关系统中将其从右向左平移,以便它实际上看起来是静止的。此时,虽然我没有更改模型层的最终值(下方项目中的注释行),但动画按预期水平运行。如果我不必同时修改模型层,我的目标就会达到,因为这正是我想要的动画。不过……

  2. ...如果我尝试设置动画的最终值(只需将这些行注释掉),我会得到意想不到的行为。在动画的初始帧,红色、蓝色和灰色层看起来相互折叠,因此旋转不再像预期的那样工作。以下是时间 0.0、0.5 和 1.0(持续时间:1.0)的一些快照:

对我来说最不合逻辑的部分是,将模型层的值设置为表示层的最终值会导致错误,但它只会影响表示层,因为一旦动画结束,下面的模型层就会在预期中 (和想要的)旋转/位置:

当旋转围绕正确的点进行时,锚点肯定是正确放置的。我认为这可能与问题 1 有关,但我尝试多次重新定位图层但没有成功。直到今天,这仍然没有解决,两天后我无法找到主要问题并因此修复它。对我来说,原始项目(上图)和旋转后的项目(下图)在引擎盖下的逻辑看起来是一样的。

EDIT2:我发现了代码中的一个小错误,我是从等于 perspectiveLayer x 位置而不是他自己的 x 位置的起始值为 firstJointLayer x 位置设置动画,我'已修复,但没有任何改变。

EDIT3:由于将模型层的值设置为等于动画最终值是导致错误的原因,请注意使用animation.fillMode = CAMediaTimingFillMode.forwardsanimation.isRemovedOnCompletion = false 不是避免触摸的可行解决方法模态层,因为我需要稍后恢复动画,因此需要保持演示层和模型层同步。

非常感谢任何帮助。下面是旋转项目 - 我还评论了我从上面的项目中更改的块:

  class ViewController: UIViewController {
    
var transform: CATransform3D = CATransform3DIdentity
var topSleeve: CALayer = CALayer()
var middleSleeve: CALayer = CALayer()
var bottomSleeve: CALayer = CALayer()
var topShadow: CALayer = CALayer()
var middleShadow: CALayer = CALayer()
let width: CGFloat = 200
let height: CGFloat = 300
var firstJointLayer: CALayer = CATransformLayer()
var secondJointLayer: CALayer = CATransformLayer()
var sizeWidth: CGFloat = 0
var positionX: CGFloat = 0
var firstJointLayerPositionX: CGFloat = 0


var perspectiveLayer: CALayer = {
    let perspectiveLayer = CALayer()
    perspectiveLayer.speed = 0.0
    perspectiveLayer.fillMode = .removed
    return perspectiveLayer
}()

var mainView: UIView = {
    let view = UIView()
    return view
}()

private let slider: UISlider = {
    let slider = UISlider()
    slider.addTarget(self, action: #selector(slide(sender:event:)) , for: .valueChanged)
    return slider
}()

override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(slider)
    setupLayers()
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    slider.frame = CGRect(x: view.bounds.size.width/3,
                          y: view.bounds.size.height/10*8,
                          width: view.bounds.size.width/3,
                          height: view.bounds.size.height/10)

}

@objc private func slide(sender: UISlider, event: UIEvent) {
    if let touchEvent = event.allTouches?.first {
        
        switch touchEvent.phase {
        case .ended:
            resumeLayer(layer: perspectiveLayer)
        default:
                perspectiveLayer.timeOffset = CFTimeInterval(sender.value)

        }
        
    }
}

private func resumeLayer(layer: CALayer) {
    let pausedTime = layer.timeOffset
    layer.speed = 1.0
    layer.timeOffset = 0.0
    layer.beginTime = 0.0
    let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
    layer.beginTime = timeSincePause
}

private func setupLayers() {
    
   // Changing all anchor points and positions here, in order to rotate the whole thing of -90°

    mainView = UIView(frame:CGRect(x: 50, y: 50, width: width*3, height: height))
    mainView.backgroundColor = UIColor.yellow
    view.addSubview(mainView)
    
    perspectiveLayer.frame = CGRect(x: width, y: 0, width: width*2, height: height)
    perspectiveLayer.backgroundColor = UIColor.cyan.cgColor
    mainView.layer.addSublayer(perspectiveLayer)
    
    firstJointLayer.fillMode = .removed
    firstJointLayer.frame = mainView.bounds
    firstJointLayer.anchorPoint = CGPoint(x: 1, y: 0.5)
    firstJointLayer.position = CGPoint(x: width*2, y: height/2)
    perspectiveLayer.addSublayer(firstJointLayer)
    
    topSleeve.fillMode = .removed
    topSleeve.frame = CGRect(x: 0, y: 0, width: width, height: height)
    topSleeve.anchorPoint = CGPoint(x: 1, y: 0.5)
    topSleeve.backgroundColor = UIColor.red.cgColor
    topSleeve.position = CGPoint(x: width*3, y: height/2)
    firstJointLayer.addSublayer(topSleeve)
    topSleeve.masksToBounds = true
    
    secondJointLayer.fillMode = .removed
    secondJointLayer.frame = mainView.bounds
    secondJointLayer.frame = CGRect(x: 0, y: 0, width: width*2, height: height)
    secondJointLayer.anchorPoint = CGPoint(x: 1, y: 0.5)
    secondJointLayer.position = CGPoint(x: width*2, y: height/2)
    firstJointLayer.addSublayer(secondJointLayer)
    
    secondJointLayer.fillMode = .removed
    middleSleeve.frame = CGRect(x: 0, y: 0, width: width, height: height)
    middleSleeve.anchorPoint = CGPoint(x: 1, y: 0.5)
    middleSleeve.backgroundColor = UIColor.blue.cgColor
    middleSleeve.position = CGPoint(x: width*2, y: height/2)
    secondJointLayer.addSublayer(middleSleeve)
    middleSleeve.masksToBounds = true
    
    bottomSleeve.fillMode = .removed
    bottomSleeve.frame = CGRect(x: 0, y: 0, width: width, height: height)
    bottomSleeve.anchorPoint = CGPoint(x: 1, y: 0.5)
    bottomSleeve.backgroundColor = UIColor.gray.cgColor
    bottomSleeve.position = CGPoint(x: width, y: height/2)
    secondJointLayer.addSublayer(bottomSleeve)
    
    topShadow.fillMode = .removed
    topSleeve.addSublayer(topShadow)
    topShadow.frame = topSleeve.bounds
    topShadow.backgroundColor = UIColor.black.cgColor
    topShadow.opacity = 0
    
    middleShadow.fillMode = .removed
    middleSleeve.addSublayer(middleShadow)
    middleShadow.frame = middleSleeve.bounds
    middleShadow.backgroundColor = UIColor.black.cgColor
    middleShadow.opacity = 0
    
    transform.m34 = -1/700
    perspectiveLayer.sublayerTransform = transform
    
    sizeWidth = perspectiveLayer.bounds.size.width
    positionX = perspectiveLayer.position.x
    firstJointLayerPositionX = firstJointLayer.position.x

    
    animate()
}


private func animate() {
    
    CATransaction.begin()
    
    CATransaction.setDisableActions(true)
    
    CATransaction.setCompletionBlock{ [weak self] in
        if self == nil { return }
        self?.perspectiveLayer.speed = 0
    }
    
  //        firstJointLayer.transform = CATransform3DMakeRotation(CGFloat(-85*Double.pi/180), 0, 1, 0)
  //        secondJointLayer.transform = CATransform3DMakeRotation(CGFloat(170*Double.pi/180), 0, 1, 0)
  //        bottomSleeve.transform = CATransform3DMakeRotation(CGFloat(-165*Double.pi/180), 0, 1, 0)
  //        perspectiveLayer.bounds.size.width = 0
  //        perspectiveLayer.position.x = 600
  //        firstJointLayer.position.x = 0
  //        topShadow.opacity = 0.5
  //        middleShadow.opacity = 0.5
    
    var animation = CABasicAnimation(keyPath: "transform.rotation.y")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = -85*Double.pi/180
    firstJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "transform.rotation.y")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 170*Double.pi/180
    secondJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "transform.rotation.y")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = -165*Double.pi/180
    bottomSleeve.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "bounds.size.width")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = sizeWidth
    animation.toValue = 0
    perspectiveLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "position.x")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = positionX
    animation.toValue = 600
    perspectiveLayer.add(animation, forKey: nil)

  // As said above, i added this animation which is not included in the original project, as the firstJointLayer was translating his position from left to right along with the perspectiveLayer position, so i make a reverse translation in its relative system so that it is stationary in the mainView system

    animation = CABasicAnimation(keyPath: "position.x")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = firstJointLayerPositionX 
    animation.toValue = 0
    firstJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "opacity")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 0.5
    topShadow.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "opacity")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 0.5
    middleShadow.add(animation, forKey: nil)
    
    CATransaction.commit()

}

}

【问题讨论】:

  • 不太清楚...留下您的评论行评论,您是否获得了您想要的开始和动画,如下所示:imgur.com/a/0xRXrWP?但是,您的目标是让它“折叠到中心”而不是从左到右折叠?
  • @DonMag 我很抱歉不清楚,我已经编辑了顶部的帖子以显示我想要的动画的一些快照。基本上我想要与注释行完全相同的动画,从左到右折叠(与我从中获取逻辑的链接问题的原始项目相反,其动画从下到上折叠)。这里的问题是,一旦您注释掉这些行,表示层就会变得疯狂,我不知道为什么。
  • hmm... 您在编辑中链接到的图像“我想要的动画” 似乎正是我在运行您的代码时看到的,如图所示我链接到的图片?
  • 注释行应该完成什么?问题是动画完成后,它会弹回“平面”并且您希望它保持“折叠”吗?
  • 转换是累积的——所以虽然它似乎应该可以工作,但我认为问题在于这种组合并没有真正做到看起来合乎逻辑的事情。如果您的目标是在动画结束时保留变换,请将那些注释行保留注释,并尝试将所有动画设置为 animation.fillMode = CAMediaTimingFillMode.forwardsanimation.isRemovedOnCompletion = false

标签: ios swift core-animation calayer cabasicanimation


【解决方案1】:

好的 - 有点玩...

看起来您需要翻转动画,因为它们实际上是在“倒退”。

private func animate() {
    
    CATransaction.begin()
    
    CATransaction.setDisableActions(true)
    
    CATransaction.setCompletionBlock{ [weak self] in
        if self == nil { return }
        //self?.perspectiveLayer.speed = 0
    }
    
    firstJointLayer.transform = CATransform3DMakeRotation(CGFloat(-85*Double.pi/180), 0, 1, 0)
    secondJointLayer.transform = CATransform3DMakeRotation(CGFloat(170*Double.pi/180), 0, 1, 0)
    bottomSleeve.transform = CATransform3DMakeRotation(CGFloat(-165*Double.pi/180), 0, 1, 0)
    perspectiveLayer.bounds.size.width = 0
    perspectiveLayer.position.x = 600
    firstJointLayer.position.x = 0
    topShadow.opacity = 0.5
    middleShadow.opacity = 0.5

    var animation = CABasicAnimation(keyPath: "transform.rotation.y")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = -85*Double.pi/180
    firstJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "transform.rotation.y")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    // flip 180 degrees
    animation.fromValue = 180*Double.pi/180
    // to 180 - 170
    animation.toValue = 10*Double.pi/180
    secondJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "transform.rotation.y")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    // flip -180 degrees
    animation.fromValue = -180*Double.pi/180
    // to 180 - 165
    animation.toValue = -15*Double.pi/180
    bottomSleeve.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "bounds.size.width")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = sizeWidth
    animation.toValue = 0
    perspectiveLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "position.x")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = positionX
    animation.toValue = 600
    perspectiveLayer.add(animation, forKey: nil)
    
    // As said above, i added this animation which is not included in the original project, as the firstJointLayer was translating his position from left to right along with the perspectiveLayer position, so i make a reverse translation in its relative system so that it is stationary in the mainView system
    
    animation = CABasicAnimation(keyPath: "position.x")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = firstJointLayerPositionX
    animation.toValue = 0
    firstJointLayer.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "opacity")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 0.5
    topShadow.add(animation, forKey: nil)
    
    animation = CABasicAnimation(keyPath: "opacity")
    animation.fillMode = CAMediaTimingFillMode.removed
    animation.duration = 1
    animation.fromValue = 0
    animation.toValue = 0.5
    middleShadow.add(animation, forKey: nil)
    
    CATransaction.commit()
    
}

【讨论】:

  • 成功了,非常感谢老兄,您一直很有耐心,非常乐于助人!真的很感激 :) 不知道为什么我以前没有测试过这个,我想我调整了 toValue 但从来没有调整过 fromValue,我的错
最近更新 更多