CALayer 介绍 无
CALayer Presentation nil
我正在尝试将 CABasicAnimation
用于自定义对象的计时功能(不是 UIView
)。
我正在尝试实现来自 here 的@CIFilter 的回答,即使用动画化的 CALayer
表示层来评估计时功能。
我在 viewDidAppear
中完成所有操作,因此存在有效视图,但无论我做什么,Presentation
层始终为零。
请注意,我必须将动画添加到视图的层,而不是我添加到它的层才能使其完全动画。如果我取消注释下面注释掉的行,我可以看到动画有效(但仅在为根层设置动画时)。无论如何,Presentation
层为零。
我看了很多教程和 SO 答案,看来这应该行得通,所以我想我一定是在做一些愚蠢的事情。
我只是想使用 CoreAnimation
计时功能。我有 UICubicTimingParameters
工作,但似乎走 CA
路线提供了更多的功能,这很好。
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let newView = UIView(frame: view.frame)
view.addSubview(newView)
let evaluatorLayer = CALayer()
evaluatorLayer.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
evaluatorLayer.borderWidth = 8.0
evaluatorLayer.borderColor = UIColor.purple.cgColor
evaluatorLayer.timeOffset = 0.3
evaluatorLayer.isHidden = true
// evaluatorLayer.isHidden = false
newView.layer.addSublayer(evaluatorLayer)
let basicAnimation = CABasicAnimation(keyPath: "bounds.origin.x")
basicAnimation.duration = 1.0
basicAnimation.fromValue = 0.0
basicAnimation.toValue = 100.0
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
basicAnimation.speed = 0.0
// basicAnimation.speed = 0.1
newView.layer.add(basicAnimation, forKey: "evaluate")
if let presentationLayer = newView.layer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("evaluatedValue: \(evaluatedValue)")
}
else {
print(evaluatorLayer.presentation())
}
}
}
不确定您的代码是否会按预期执行,但是...
我认为 .presentation()
是 nil
的原因是你没有给 UIKit
应用动画的机会。
试试这个:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let newView = UIView(frame: view.frame)
view.addSubview(newView)
let evaluatorLayer = CALayer()
evaluatorLayer.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
evaluatorLayer.borderWidth = 8.0
evaluatorLayer.borderColor = UIColor.purple.cgColor
evaluatorLayer.timeOffset = 0.3
evaluatorLayer.isHidden = true
// evaluatorLayer.isHidden = false
newView.layer.addSublayer(evaluatorLayer)
let basicAnimation = CABasicAnimation(keyPath: "bounds.origin.x")
basicAnimation.duration = 1.0
basicAnimation.fromValue = 0.0
basicAnimation.toValue = 100.0
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
basicAnimation.speed = 0.0
// basicAnimation.speed = 0.1
newView.layer.add(basicAnimation, forKey: "evaluate")
DispatchQueue.main.async {
if let presentationLayer = newView.layer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("async evaluatedValue: \(evaluatedValue)")
}
else {
print("async", evaluatorLayer.presentation())
}
}
if let presentationLayer = newView.layer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("immediate evaluatedValue: \(evaluatedValue)")
}
else {
print("immediate", evaluatorLayer.presentation())
}
}
我的调试输出是:
immediate nil
async evaluatedValue: 0.0
编辑
我仍然不确定你的目标是什么,但试一试...
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let newView = UIView(frame: view.frame)
view.addSubview(newView)
let evaluatorLayer = CALayer()
evaluatorLayer.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
evaluatorLayer.borderWidth = 8.0
evaluatorLayer.borderColor = UIColor.purple.cgColor
evaluatorLayer.isHidden = true
//evaluatorLayer.isHidden = false
newView.layer.addSublayer(evaluatorLayer)
let basicAnimation = CABasicAnimation(keyPath: "bounds.origin.x")
basicAnimation.duration = 1.0
basicAnimation.fromValue = 0.0
basicAnimation.toValue = 100.0
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
basicAnimation.speed = 0.0
//basicAnimation.speed = 1.0
// set timeOffset on the animation, not on the layer itself
basicAnimation.timeOffset = 0.3
// add animation to evaluatorLayer
evaluatorLayer.add(basicAnimation, forKey: "evaluate")
DispatchQueue.main.async {
// get presentation layer of evaluatorLayer
if let presentationLayer = evaluatorLayer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("async evaluatedValue: \(evaluatedValue)")
}
else {
print("async", evaluatorLayer.presentation())
}
}
}
在此示例中,我们将 .timeOffset
应用于动画,而不是图层。而且,我们将动画添加到 evaluatorLayer
,而不是 newView.layer
。
输出(用于我的快速测试):
async evaluatedValue: 30.000001192092896
我正在尝试将 CABasicAnimation
用于自定义对象的计时功能(不是 UIView
)。
我正在尝试实现来自 here 的@CIFilter 的回答,即使用动画化的 CALayer
表示层来评估计时功能。
我在 viewDidAppear
中完成所有操作,因此存在有效视图,但无论我做什么,Presentation
层始终为零。
请注意,我必须将动画添加到视图的层,而不是我添加到它的层才能使其完全动画。如果我取消注释下面注释掉的行,我可以看到动画有效(但仅在为根层设置动画时)。无论如何,Presentation
层为零。
我看了很多教程和 SO 答案,看来这应该行得通,所以我想我一定是在做一些愚蠢的事情。
我只是想使用 CoreAnimation
计时功能。我有 UICubicTimingParameters
工作,但似乎走 CA
路线提供了更多的功能,这很好。
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let newView = UIView(frame: view.frame)
view.addSubview(newView)
let evaluatorLayer = CALayer()
evaluatorLayer.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
evaluatorLayer.borderWidth = 8.0
evaluatorLayer.borderColor = UIColor.purple.cgColor
evaluatorLayer.timeOffset = 0.3
evaluatorLayer.isHidden = true
// evaluatorLayer.isHidden = false
newView.layer.addSublayer(evaluatorLayer)
let basicAnimation = CABasicAnimation(keyPath: "bounds.origin.x")
basicAnimation.duration = 1.0
basicAnimation.fromValue = 0.0
basicAnimation.toValue = 100.0
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
basicAnimation.speed = 0.0
// basicAnimation.speed = 0.1
newView.layer.add(basicAnimation, forKey: "evaluate")
if let presentationLayer = newView.layer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("evaluatedValue: \(evaluatedValue)")
}
else {
print(evaluatorLayer.presentation())
}
}
}
不确定您的代码是否会按预期执行,但是...
我认为 .presentation()
是 nil
的原因是你没有给 UIKit
应用动画的机会。
试试这个:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let newView = UIView(frame: view.frame)
view.addSubview(newView)
let evaluatorLayer = CALayer()
evaluatorLayer.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
evaluatorLayer.borderWidth = 8.0
evaluatorLayer.borderColor = UIColor.purple.cgColor
evaluatorLayer.timeOffset = 0.3
evaluatorLayer.isHidden = true
// evaluatorLayer.isHidden = false
newView.layer.addSublayer(evaluatorLayer)
let basicAnimation = CABasicAnimation(keyPath: "bounds.origin.x")
basicAnimation.duration = 1.0
basicAnimation.fromValue = 0.0
basicAnimation.toValue = 100.0
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
basicAnimation.speed = 0.0
// basicAnimation.speed = 0.1
newView.layer.add(basicAnimation, forKey: "evaluate")
DispatchQueue.main.async {
if let presentationLayer = newView.layer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("async evaluatedValue: \(evaluatedValue)")
}
else {
print("async", evaluatorLayer.presentation())
}
}
if let presentationLayer = newView.layer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("immediate evaluatedValue: \(evaluatedValue)")
}
else {
print("immediate", evaluatorLayer.presentation())
}
}
我的调试输出是:
immediate nil
async evaluatedValue: 0.0
编辑
我仍然不确定你的目标是什么,但试一试...
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let newView = UIView(frame: view.frame)
view.addSubview(newView)
let evaluatorLayer = CALayer()
evaluatorLayer.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
evaluatorLayer.borderWidth = 8.0
evaluatorLayer.borderColor = UIColor.purple.cgColor
evaluatorLayer.isHidden = true
//evaluatorLayer.isHidden = false
newView.layer.addSublayer(evaluatorLayer)
let basicAnimation = CABasicAnimation(keyPath: "bounds.origin.x")
basicAnimation.duration = 1.0
basicAnimation.fromValue = 0.0
basicAnimation.toValue = 100.0
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
basicAnimation.speed = 0.0
//basicAnimation.speed = 1.0
// set timeOffset on the animation, not on the layer itself
basicAnimation.timeOffset = 0.3
// add animation to evaluatorLayer
evaluatorLayer.add(basicAnimation, forKey: "evaluate")
DispatchQueue.main.async {
// get presentation layer of evaluatorLayer
if let presentationLayer = evaluatorLayer.presentation() {
let evaluatedValue = presentationLayer.bounds.origin.x
print("async evaluatedValue: \(evaluatedValue)")
}
else {
print("async", evaluatorLayer.presentation())
}
}
}
在此示例中,我们将 .timeOffset
应用于动画,而不是图层。而且,我们将动画添加到 evaluatorLayer
,而不是 newView.layer
。
输出(用于我的快速测试):
async evaluatedValue: 30.000001192092896