【问题标题】:CALayer resizing back to original size after transform animation变换动画后,CALayer 将大小调整回原始大小
【发布时间】:2017-07-20 04:39:22
【问题描述】:

我正在尝试实现两个连续的变换动画。当第一个动画结束时,通过完成处理程序调用第二个动画。因为这是一个变换动画,所以我的问题是当第一个动画结束时,图层会调整回原来的大小,然后第二个动画开始。我希望第二个动画在第一个转换动画之后以新的图层大小开始。这篇帖子Objective-C - CABasicAnimation applying changes after animation? 说我必须在开始第一个动画之前调整图层的大小/变换,这样当第一个动画结束时,图层实际上是新的大小。我尝试通过更改边界或将变换实际应用于图层来做到这一点,但它仍然无法正常工作。

override func viewDidAppear(_ animated: Bool) {

    buildBar()   

}

func buildBar(){

    progressBar1.bounds = CGRect(x: 0, y: 0, width: 20, height: 5)
    progressBar1.position = CGPoint(x: 0, y: 600)
    progressBar1.backgroundColor = UIColor.white.cgColor
    view.layer.addSublayer(progressBar1)
    extendBar1()

}


func extendBar1(){

     CATransaction.begin()

     let transform1 = CATransform3DMakeScale(10, 1, 1)
     let anim = CABasicAnimation(keyPath: "transform")
     // self.progressBar1.bounds = CGRect(x: 0, y: 0, width: 200, height: 5)
     // self.progressBar1.transform = transform1
     anim.isRemovedOnCompletion = false
     anim.fillMode = kCAFillModeForwards
     anim.toValue = NSValue(caTransform3D:transform1)
     anim.duration = 5.00

     CATransaction.setCompletionBlock {

         self.extendBar2()
     }

     progressBar1.add(anim, forKey: "transform")
     CATransaction.commit()
}

func extendBar2(){

     let transform1 = CATransform3DMakeScale(2, 1, 1)
     let anim = CABasicAnimation(keyPath: "transform")
     anim.isRemovedOnCompletion = false
     anim.fillMode = kCAFillModeForwards
     anim.toValue = NSValue(caTransform3D:transform1)
     anim.duration = 5.00
     progressBar1.add(anim, forKey: "transform")

}

【问题讨论】:

    标签: ios swift3 calayer cabasicanimation


    【解决方案1】:

    因为您在两个动画中都修改了图层的 transform 属性,所以在这里使用CAKeyframeAnimation 会更容易,它将为您处理动画的链接。

    func extendBar(){
         let transform1 = CATransform3DMakeScale(10, 1, 1)
         let transform2 = CATransform3DMakeScale(2, 1, 1)
    
         let anim = CAKeyframeAnimation()
         anim.keyPath = "transform"
         anim.values = [progressBar1.transform, transform1, transform2] // the stages of the animation
         anim.keyTimes = [0, 0.5, 1] // when they occurs, 0 being the very begining, 1 the end
         anim.duration = 10.00
    
         progressBar1.add(anim, forKey: "transform")
         progressBar1.transform = transform2 // we set the transform property to the final animation's value
    }
    

    说说valueskeyTimes的内容:

    • 我们将第一个值设置为progressBar1 的当前变换。这将确保我们从当前层的状态开始。
    • keyTimes 中,我们说一开始应该使用values 数组中的第一个值。然后我们说在动画的一半时间,图层应该转换为values 秒值。因此,初始状态和第二个状态之间的动画将在此期间发生。然后,在 0.5 到 1 之间,我们将从 tranform1 变为 transform2

    您可以在 objc.io 的 this very nice article 中阅读有关动画的更多信息。


    如果你真的需要两个不同的动画(因为也许你想在两者之间添加子视图到progressBar1,这里的代码可以做到这一点

    func extendBar1() {
        CATransaction.begin()
        CATransaction.setCompletionBlock {
            print("side effects")
            extendBar2()
        }
        let transform1 = CATransform3DMakeScale(5, 1, 1)
        let anim = CABasicAnimation(keyPath: "transform")
    
        anim.fromValue = progressBar1.transform
        anim.toValue = transform1
        anim.duration = 2.00
        progressBar1.add(anim, forKey: "transform")
        CATransaction.setDisableActions(true)
        progressBar1.transform = transform1
        CATransaction.commit()
    }
    
    func extendBar2() {
        CATransaction.begin()
        let transform2 = CATransform3DMakeScale(2, 1, 1)
        let anim = CABasicAnimation(keyPath: "transform")
    
        anim.fromValue = progressBar1.transform
        anim.toValue = transform2
        anim.duration = 2.00
        progressBar1.add(anim, forKey: "transform")
        CATransaction.setDisableActions(true)
        progressBar1.transform = transform2
        CATransaction.commit()
    }
    

    这里发生了什么?基本上,我们设置了第一个“正常动画”。所以我们创建了动画,它将修改表示层并将实际层设置为最终第一个动画的变换。

    然后,当第一个动画完成时,我们调用extendBar2,它会依次将正常动画排队。

    您还想在显式更新变换之前调用CATransaction.setDisableActions(true),否则,核心动画将创建一个隐式动画,它将覆盖之前创建的动画。

    【讨论】:

    • 是否可以使用完成处理程序?我试图在两个动画之间做点什么,这就是我有完成处理程序的原因。
    • 嗯,不,当达到关键帧动画的某些点时,您没有回调。让我用两个不同的动画来扩展我的答案,以便您可以使用完成处理程序。
    • @Brosef 一分钟变成了 12 分钟,但答案已更新 :)
    • 这对你有用吗?对我来说,在第一个动画之后,它会向后动画到原始大小。
    • 是的,刚刚在操场上试了一下,一切正常。
    猜你喜欢
    • 1970-01-01
    • 2017-03-03
    • 2016-12-01
    • 1970-01-01
    • 2015-06-28
    • 2012-08-07
    • 2013-11-02
    • 1970-01-01
    • 2012-09-19
    相关资源
    最近更新 更多