简体   繁体   English

当我更改 model 层的属性时 animation 中的意外行为

[英]Unexpected behaviour in animation when i change the properties of the model layers

Referring to this post, i'm trying to adapt the animations to landscape mode.参考这篇文章,我正在尝试将动画调整为横向模式。 Basically what i want is to rotate all layers of -90° (90° clockwise) and the animations to run horizontally instead of vertically.基本上我想要的是旋转-90°(顺时针90°)的所有图层,并且动画水平运行而不是垂直运行。 The author didn't bother to explain the logic under the hood, there are a dozen paper folding libraries in obj-c which are all based on the same architecture, so apparently this is the way to go for folding.作者没有费心解释背后的逻辑,obj-c 中有十几个纸张折叠库,它们都基于相同的架构,所以显然这是 go 进行折叠的方式。

EDIT : To further clarify what i want to achieve, here you can look at three snapshots (starting point, halftime and ending point) of the animations i want.编辑:为了进一步阐明我想要实现的目标,在这里您可以查看我想要的动画的三个快照(起点、半场和终点)。 In the question from the link up above the animation collapses from bottom to top, while i want it to collapse from left to right.在上面链接的问题中,animation 从下到上折叠,而我希望它从左到右折叠。

Down below you can take a look at the the original project a bit tweaked:在下面,您可以查看稍加调整的原始项目:

  • i changed the gray bottomSleeve layer final angle value, as well as the red and blue ones angle;我改变了灰色bottomSleeve层的最终角度值,以及红色和蓝色的角度;
  • i paused the animations on initialization by setting the perspectiveLayer speed equal to 0 and added a slider, the slider value is then set equal to the perspectiveLayer timeOffset so that you can interactively run each frame of the animations by sliding.我通过将perspectiveLayer speed设置为0来暂停动画初始化并添加了 slider,然后将 slider 值设置为等于perspectiveLayer timeOffset以便您可以通过滑动交互地运行动画的每一帧。 When the touch event on the slider ends, the animations are then resumed from the frame relative to the current timeOffset to the final value.当 slider 上的触摸事件结束时,动画将从相对于当前timeOffset的帧恢复到最终值。
  • i changed all the model layers values before running each animation added to the relative presentation layer using CATransaction .在运行使用CATransaction添加到相关表示层的每个 animation 之前,我更改了所有 model 层值。 Also, on completion the perspectiveLayer speed is set to 0 again.此外,完成后, perspectiveLayer速度再次设置为0
  • for a better visual understanding, i set the perspectiveLayer backgroundColor equal to cyan .为了更好的视觉理解,我将perspectiveLayer backgroundColor设置为cyan

Just to point it out, there are two main functions:只是指出,有两个主要功能:

  1. setupLayers() , called in viewDidLoad() is responsible of setting up the layers positions and anchor points, as well as adding them as sublayers to the mainView layer.viewDidLoad()中调用的setupLayers()负责设置图层位置和锚点,以及将它们作为子图层添加到mainView图层。
  2. animate() , called recursively in setupLayers() , responsible of adding the animations. animate() ,在setupLayers()中递归调用,负责添加动画。 Here i also set the model layers values to the related animations final value before adding them.在这里,我还将 model 图层值设置为相关动画的最终值,然后再添加它们。

Just copy, paste it and run:只需复制、粘贴并运行:

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()

}
}

As you can see the animations run as expected, at this point in order to rotate the whole thing it should be just a matter of changing positions, anchor points and final animations values.如您所见,动画按预期运行,此时要旋转整个物体,只需更改位置、锚点和最终动画值即可。 Taken from an answer from the link above, here is a great representation of all the layers of the starting project:摘自上面链接的答案,这是起始项目所有层的一个很好的表示:

在此处输入图像描述

Then i proceeded to refactor setupLayers() and animate() to run the animations horizontally, from left to right (in other words, i'm rotating of 90° clockwise the up above layers representation).然后我继续重构setupLayers()animate()以水平运行动画,从左到右(换句话说,我在上面的图层表示中顺时针旋转 90°)。

Once the code is changed to rotate the animations, i encounter two issues:更改代码以旋转动画后,我遇到两个问题:

  1. when the animations start, the firstJointLayer position translate from left to right along the perspectiveLayer .当动画开始时, firstJointLayer position 沿着perspectiveLayer从左向右平移。 To be fair to my understanding this should be an expected behaviour, as it is a sublayer of perspectiveLayer , actually i'm not sure why in the original project it doesn't happen.公平地说,这应该是一种预期的行为,因为它是perspectiveLayer的子层,实际上我不确定为什么在原始项目中它不会发生。 However, to fix this, i've added another animation responsible of translating it from right to left in its relative system, so that it actually appears stationary.然而,为了解决这个问题,我添加了另一个 animation 负责在其相关系统中将其从右向左翻译,因此它实际上看起来是静止的。 At this point while i don't change the model layers final values (commented lines in the down below project), the animations run horizontally as expected.此时,虽然我没有更改 model 图层的最终值(下方项目中的注释行),但动画按预期水平运行。 If i didn't have to also modify the model layers, my goal would be reached as this is the exact animation i want.如果我不必同时修改 model 层,我的目标就会实现,因为这正是我想要的 animation。 However...然而...

  2. ...if i then try to set the animations final values (just comment the lines out) i get an unexpected behaviour. ...如果我然后尝试设置动画的最终值(只需将这些行注释掉)我会得到一个意想不到的行为。 At the initial frame of the animations, the red, blue and gray layers appear folded on each other, thus the rotations don't work as predicted anymore.在动画的初始帧,红色、蓝色和灰色层看起来相互折叠,因此旋转不再像预期的那样工作。 Here are some snapshots at time 0.0, 0.5 and 1.0 (duration: 1.0):以下是时间 0.0、0.5 和 1.0(持续时间:1.0)的一些快照:

The most illogical part to me is that setting the model layers values equal to the presentation layers final values causes the bug, but it only affects the presentation layers, as once the animations are over the model layers below are in the expected (and wanted) rotation/position:对我来说最不合逻辑的部分是设置 model 层的值等于表示层的最终值会导致错误,但它只会影响表示层,因为一旦动画结束,下面的 model 层是预期的(和想要的)旋转/位置: 在此处输入图像描述

The anchor points are for sure placed right as the rotations happen around the correct points.当旋转围绕正确的点进行时,锚点肯定会正确放置。 I think it may be related to issue 1., but i've tried to reposition the layers multiple times with no success.我认为这可能与问题 1 有关,但我尝试多次重新定位图层但没有成功。 To the present day this is still unsolved, in two days i wasn't able to track down the primary issue and thus to fix it.直到今天,这仍然没有解决,两天后我无法找到主要问题并因此修复它。 To me the original project (up above) and the rotated project (down below) look the same in the logic under the hood.对我来说,原始项目(上方)和旋转项目(下方)在引擎盖下的逻辑中看起来相同。

EDIT2: i've found out a minor bug in the code, i was animating the firstJointLayer x position from a starting value equal to the perspectiveLayer x position instead of his own x position, i've fixed it but nothing changed. EDIT2:我在代码中发现了一个小错误,我正在为 firstJointLayer x position 设置动画,起始值等于 perspectiveLayer x position 而不是他自己的 x Z4757FE07FD0 已修复,但没有任何改变。6

EDIT3 : Since setting the model layers values equal to the animation final values is what causes the bug, please note that using animation.fillMode = CAMediaTimingFillMode.forwards and animation.isRemovedOnCompletion = false is not a viable workaround for avoiding to touch the modal layers, as i need to revert the animation at a later time thus keeping presentation and model layers synced is required. EDIT3 : Since setting the model layers values equal to the animation final values is what causes the bug, please note that using animation.fillMode = CAMediaTimingFillMode.forwards and animation.isRemovedOnCompletion = false is not a viable workaround for avoiding to touch the modal layers,因为我需要稍后恢复 animation,因此需要保持演示和 model 层同步。

Any help is really appreciated.非常感谢任何帮助。 Down here the rotated project - i've also commented the blocks i've changed from the up above project:下面是旋转项目 - 我还评论了我从上面的项目中更改的块:

  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()

}

}

OK - a bit of playing around...好吧 - 有点玩...

Looks like you need to flip the animations, since they're effectively "going backward."看起来您需要翻转动画,因为它们实际上是在“倒退”。

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()
    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 UIViewAnimationOptionBeginFromCurrentState具有基本动画的意外行为 - UIViewAnimationOptionBeginFromCurrentState unexpected behaviour with basic animation Scenekit:动画时模型更改大小 - Scenekit: Model change size when animation 将子视图添加到UICollectionViewCell时发生意外行为 - Unexpected behaviour when adding subviews to UICollectionViewCell 推送时隐藏BottomBarWhenPushed奇怪的动画行为 - hidesBottomBarWhenPushed weird animation behaviour when push 当我在模型中使用 withAnimation 时,没有动画发生,为什么? - When I use withAnimation in the Model, no animation happens, why? 按顺序更改UIView的属性,但没有动画? - Change a properties of UIView in sequence, but without animation? CAAnimation - 在 animation 的最后一帧中更改属性? - CAAnimation - change properties in the last frame of the animation? 更改viewcontroller时,uiwebView本地文件html动画问题 - uiwebView local file html animation problems when I change viewcontroller 为什么在给UIImageView动画时UIImage参考会更改? - Why UIImage reference change when i give animation to UIImageView? 使用AVVideoCompositionCoreAnimationTool时如何更改动画层的子层 - How can I change sublayers of animation layer when using AVVideoCompositionCoreAnimationTool
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM