我不知道是否可以直接实现,因为NSLayoutConstraint是UIKit的一部分,而CALayer是Core Animation的一部分。但对我来说,这种方法可行,我使用自定义三次贝塞尔动画曲线来进行CABasicAnimation,然后在完成时,UIView返回到动画开始之前由其约束定义的起始位置(或者我可以在动画完成块中设置其他约束到我的UIView),如果你想玩一下,可以将以下内容粘贴到空的新项目中:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
super.view.backgroundColor = .white
let button: UIButton = {
let button = UIButton()
super.view.addSubview(button)
button.setTitleColor(UIColor.systemCyan, for: .normal)
button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
button.setTitle("Animate!", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.topAnchor.constraint(equalTo: super.view.topAnchor, constant: super.view.frame.height * 0.886),
button.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
button.heightAnchor.constraint(equalToConstant: super.view.frame.height * 0.024),
])
return button
}()
}
@objc func buttonPressed() {
for view in super.view.subviews {
if view.backgroundColor == .systemMint {
view.removeFromSuperview()
}
}
var heightConstraint: NSLayoutConstraint!
var topConstraint: NSLayoutConstraint!
let view: UIView = {
let view = UIView()
super.view.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.masksToBounds = true
view.backgroundColor = .systemMint
heightConstraint = view.heightAnchor.constraint(equalToConstant: super.view.frame.height * 0.605)
topConstraint = view.topAnchor.constraint(equalTo: super.view.topAnchor, constant: -600)
NSLayoutConstraint.activate([
topConstraint,
view.widthAnchor.constraint(equalToConstant: super.view.frame.width * 0.87),
heightConstraint,
view.centerXAnchor.constraint(equalTo: super.view.centerXAnchor)
])
view.layer.cornerRadius = super.view.frame.height * 0.0495
return view
}()
let timingFunction = CAMediaTimingFunction(controlPoints: 0,1.07,0.15,0.97 )
let animation = CABasicAnimation(keyPath: "position.y")
animation.duration = 3
animation.fromValue = -heightConstraint.constant/2
animation.toValue = heightConstraint.constant/2
animation.timingFunction = timingFunction
animation.fillMode = .forwards
animation.isRemovedOnCompletion = true
CATransaction.setCompletionBlock({
topConstraint.constant = 0
})
view.layer.add(animation, forKey: nil)
}
}
我们可以从gif中看到,在动画完成后,设置给UIView的约束得以保留。