CALayer 在变换动画后调整回原始大小
CALayer resizing back to original size after transform animation
我正在尝试实现两个连续的变换动画。当第一个动画结束时,通过完成处理程序调用第二个动画。因为这是一个转换动画,我的问题是当第一个动画结束时,图层大小调整回原来的大小,然后第二个动画开始。我希望第二个动画在第一个变换动画之后以新的图层大小开始。这个 post Objective-C - CABasicAnimation applying changes after animation? 说我必须在开始第一个动画之前 resize/transform 层,这样当第一个动画结束时,层实际上是新的大小。我已经尝试通过更改边界或实际将变换应用于图层来做到这一点,但它仍然无法正常工作。
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")
}
因为您正在修改两个动画中层的变换 属性,所以在这里使用 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
}
关于values
和keyTimes
内容的一句话:
- 我们将第一个值设置为
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()
}
这里发生了什么?基本上,我们先设置一个 "normal animation"。所以我们创建动画,这将修改 表示层 并将实际层设置为最终第一个动画的变换。
然后,当第一个动画完成时,我们调用 extendBar2
,这将轮流排队一个普通的动画。
您还想在显式更新变换之前调用 CATransaction.setDisableActions(true)
,否则,核心动画将创建一个隐式动画,它将覆盖之前创建的动画。
我正在尝试实现两个连续的变换动画。当第一个动画结束时,通过完成处理程序调用第二个动画。因为这是一个转换动画,我的问题是当第一个动画结束时,图层大小调整回原来的大小,然后第二个动画开始。我希望第二个动画在第一个变换动画之后以新的图层大小开始。这个 post Objective-C - CABasicAnimation applying changes after animation? 说我必须在开始第一个动画之前 resize/transform 层,这样当第一个动画结束时,层实际上是新的大小。我已经尝试通过更改边界或实际将变换应用于图层来做到这一点,但它仍然无法正常工作。
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")
}
因为您正在修改两个动画中层的变换 属性,所以在这里使用 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
}
关于values
和keyTimes
内容的一句话:
- 我们将第一个值设置为
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()
}
这里发生了什么?基本上,我们先设置一个 "normal animation"。所以我们创建动画,这将修改 表示层 并将实际层设置为最终第一个动画的变换。
然后,当第一个动画完成时,我们调用 extendBar2
,这将轮流排队一个普通的动画。
您还想在显式更新变换之前调用 CATransaction.setDisableActions(true)
,否则,核心动画将创建一个隐式动画,它将覆盖之前创建的动画。