我有一堆添加到CALayer的动画。我需要知道按钮在动画时与其进行交互的位置。但框架并没有改变。 如何查找/计算值?这是代码:
let positionY = CAKeyframeAnimation(keyPath: "position.y")
positionY.values = valuesY
positionY.keyTimes = keyTimes
positionY.duration = totalTime
positionY.isAdditive = true
positionY.isRemovedOnCompletion = false
// X Position Animation
let positionX = CAKeyframeAnimation(keyPath: "position.x")
positionX.values = valuesX
positionX.keyTimes = keyTimes
positionX.duration = 5
positionX.isAdditive = true
positionX.isRemovedOnCompletion = false
// Rotation Animation
let rotation = CAKeyframeAnimation(keyPath: "transform.rotation.z")
rotation.values = valuesRotation
rotation.keyTimes = keyTimes
rotation.duration = totalTime
rotation.isAdditive = true
rotation.isRemovedOnCompletion = false
// Grouping the animations
let group = CAAnimationGroup()
group.animations = [positionX, positionY, rotation]
group.duration = totalTime
group.fillMode = kCAFillModeForwards
group.delegate = self
group.setValue(button, forKey: GiftGameVC.kAnimationKeyPath)
group.isRemovedOnCompletion = false
//
CATransaction.begin()
CATransaction.setDisableActions(false)
CATransaction.setCompletionBlock {
print("Done")
}
button.layer.add(group, forKey: GiftGameVC.kAnimationKeyPath)
CATransaction.commit()
答案 0 :(得分:0)
您需要检查按钮的presentationLayer,因为您基本上正在观看电影,并且真实的图层位置永远不会像您找到的那样发生变化。一个例子就像下面这样。此外,对于图层动画,视图的框架将永远不会更改,只有图层位置和图层框架。 UIView动画可以更新视图的框架。
import UIKit
class ViewController: UIViewController {
var timer : Timer?
var animationView = UIView()
var currentPositionLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
animationView = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
animationView.layer.cornerRadius = 15
animationView.backgroundColor = UIColor.blue
self.view.addSubview(animationView)
let button = UIButton(frame: CGRect(x: 20, y:self.view.bounds.height - 60, width: self.view.bounds.width - 40, height: 40))
button.addTarget(self, action: #selector(startAnimation), for: .touchUpInside)
button.backgroundColor = UIColor.green
button.setTitle("Restart Animation", for: .normal)
self.view.addSubview(button)
currentPositionLabel = UILabel(frame: CGRect(x: 20, y:button.frame.minY - 50, width: self.view.bounds.width - 40, height: 40))
currentPositionLabel.textColor = UIColor.gray
currentPositionLabel.adjustsFontSizeToFitWidth = true
currentPositionLabel.minimumScaleFactor = 0.01
self.view.addSubview(currentPositionLabel)
currentPositionLabel.text = "Current Position \(animationView.layer.position)"
}
@objc func startAnimation(){
//prepare to watch a movie/animation while your layer never really moves
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "position")
animation.duration = 20.0
animation.toValue = NSValue(cgPoint: CGPoint(x: self.view.bounds.width - 35, y: self.view.bounds.height - 120))
CATransaction.setCompletionBlock {
self.timer?.invalidate()
self.timer = nil
print("the real position never changed \(self.animationView.layer.position)")
self.animationView.layer.removeAllAnimations()
self.currentPositionLabel.text = "Current Position \(self.animationView.layer.position)"
}
animationView.layer.add(animation, forKey: "animationViewPosition")
//if you really want to update the real position of the layer i do it here
//self.animationView.layer.position = CGPoint(x: self.view.bounds.width - 35, y: self.view.bounds.height - 120)
//this would mean when the animation is removed that the layer is there but still would not give you the current value
//of the layer position
CATransaction.commit()
if let _ = timer{
//do nothing we are good to go
}else{
//start a new timer
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerUpdateAnimationPosition), userInfo: nil, repeats: true)
}
}
@objc func timerUpdateAnimationPosition(){
//get presentation layer
if let presLayer = self.animationView.layer.presentation(){
if let animationPosition = presLayer.value(forKeyPath: "position") as? CGPoint{
self.currentPositionLabel.text = "Animation Position : \(animationPosition)"
}
}
}
}
你可以在函数timerUpdateAnimationPosition中看到我检查了presentationLayer的动画位置。对于动画位置的互动,请参阅此answer。但如果你正在寻找它,那就意味着上面的答案也是正确的。
答案 1 :(得分:0)
你已经注意到了;为该键路径添加动画时,属性的值不会更改。如果您想知道屏幕当前显示的图层状态,您可以访问图层的presentationLayer
:
此方法返回的图层对象提供了当前在屏幕上显示的图层的近似值。当动画正在进行时,您可以检索此对象并使用它来获取这些动画的当前值。
在您的情况下,您可以使用button.layer.presentationLayer.position
获取按钮动画位置。
相关:由于您在完成动画并使用前向填充模式后停止移动动画,因此您将在“模型图层”和“表示层”之间保持这种差异。换一种说法;你让它看起来像这些属性已经改变,但实际上它们没有。这通常被认为是一种不好的做法,可能导致奇怪和无意的行为;例如,一个按钮现在可以在屏幕上显示,但同时可以在动画播放前的位置进行点播。
要避免这些类型的问题,最好在添加动画之前更新属性,使其与动画的最终值匹配。这样,“模型层”和“表示层”之间的差异仅存在于动画期间。
在您的代码中,您将删除所有.isRemovedOnCompletion = false
行和.fillMode = kCAFillModeForwards
行,而是将按钮图层的position
和transform
设置为其最终值将动画组添加到图层。