如果我想在之后为自动布局约束设置动画,我该如何修改我的 UIView 扩展?
How do I have to modify my UIView extension if I wanted to animate the auto layout constraints afterward?
我做了一个 UIView
扩展来设置我的 NSLayout
锚点。一切正常。但是,如果我想添加一个 NSLayoutConstraint
,我该如何修改我的扩展,以便之后可以为约束设置动画?
这是我当前的分机:
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {
//translate the view's autoresizing mask into Auto Layout constraints
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
}
if let trailing = trailing {
trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
}
if size.width != 0 {
widthAnchor.constraint(equalToConstant: size.width).isActive = true
}
if size.height != 0 {
heightAnchor.constraint(equalToConstant: size.height).isActive = true
}
}
}
扩展程序的调用方式如下:
//feedViewButton constraints
feedViewButton.anchor(top: nil, leading: nil, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 25), size: .init(width: 50, height: 50))
更新
我想要这样的东西
var topAnchor: NSLayoutConstraint?
topAnchor = topAnchor.constraint(equaltTo: top, constant: padding.top)
topAnchor.isActive = true
然后像这样制作动画:
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeOut) {
topAnchor.constant = 20
}
animator.startAnimation()
只需尝试使用自动布局为其制作动画,因为尚未应用约束,它应该是可动画的:
feedViewButton.anchor(top: nil, leading: nil, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 25), size: .init(width: 50, height: 50))
feedViewButton.superview?.setNeedsLayout()
UIView.animate(withDuration: 0.2, delay: 0, options: [.allowUserInteraction], animations: {
feedViewButton.superview?.layoutIfNeeded()
}, completion: nil)
更新
如果您想稍后更改锚点上的常量以动画化其他更改,则必须保留对约束的引用以便以后能够操纵它们:
enum ConstraintType {
case top, leading, trailing, bottom, width, height
}
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> [ConstraintType : NSLayoutConstraint] {
//translate the view's autoresizing mask into Auto Layout constraints
translatesAutoresizingMaskIntoConstraints = false
var constraints: [ConstraintType : NSLayoutConstraint] = [:]
if let top = top {
constraints[.top] = topAnchor.constraint(equalTo: top, constant: padding.top)
}
if let leading = leading {
constraints[.leading] = leadingAnchor.constraint(equalTo: leading, constant: padding.left)
}
if let bottom = bottom {
constraints[.bottom] = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom)
}
if let trailing = trailing {
constraints[.trailing] = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right)
}
if size.width != 0 {
constraints[.width] = widthAnchor.constraint(equalToConstant: size.width)
}
if size.height != 0 {
constraints[.height] = heightAnchor.constraint(equalToConstant: size.height)
}
let constraintsArray = Array<NSLayoutConstraint>(constraints.values)
NSLayoutConstraint.activate(constraintsArray)
return constraints
}
}
此扩展 returns 一个约束字典,您可以稍后更改这些约束并为这些更改设置动画。例如:
let constraints = feedViewButton.anchor(top: nil, leading: nil, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 25), size: .init(width: 50, height: 50))
// applies the constraints
self.view.layoutIfNeeded()
// now to animate bottom to -50:
if let bottomConstraint = constraints[.bottom] {
bottomConstraint.constant = -50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
self.view.layoutIfNeeded()
})
animator.startAnimation()
}
您可以简单地在扩展上添加动画,因此所有对 anchor
的调用都将在不添加动画块的情况下进行动画处理。
extension UIView {
func anchor(animated: Bool, top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {
//translate the view's autoresizing mask into Auto Layout constraints
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
}
if let trailing = trailing {
trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
}
if size.width != 0 {
widthAnchor.constraint(equalToConstant: size.width).isActive = true
}
if size.height != 0 {
heightAnchor.constraint(equalToConstant: size.height).isActive = true
}
if animated {
UIView.animate(withDuration: 0.2, delay: 0, options: [.allowUserInteraction], animations: {
self.layoutIfNeeded()
}, completion: nil)
} else {
self.layoutIfNeeded()
}
}
}
我做了一个 UIView
扩展来设置我的 NSLayout
锚点。一切正常。但是,如果我想添加一个 NSLayoutConstraint
,我该如何修改我的扩展,以便之后可以为约束设置动画?
这是我当前的分机:
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {
//translate the view's autoresizing mask into Auto Layout constraints
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
}
if let trailing = trailing {
trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
}
if size.width != 0 {
widthAnchor.constraint(equalToConstant: size.width).isActive = true
}
if size.height != 0 {
heightAnchor.constraint(equalToConstant: size.height).isActive = true
}
}
}
扩展程序的调用方式如下:
//feedViewButton constraints
feedViewButton.anchor(top: nil, leading: nil, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 25), size: .init(width: 50, height: 50))
更新
我想要这样的东西
var topAnchor: NSLayoutConstraint?
topAnchor = topAnchor.constraint(equaltTo: top, constant: padding.top)
topAnchor.isActive = true
然后像这样制作动画:
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeOut) {
topAnchor.constant = 20
}
animator.startAnimation()
只需尝试使用自动布局为其制作动画,因为尚未应用约束,它应该是可动画的:
feedViewButton.anchor(top: nil, leading: nil, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 25), size: .init(width: 50, height: 50))
feedViewButton.superview?.setNeedsLayout()
UIView.animate(withDuration: 0.2, delay: 0, options: [.allowUserInteraction], animations: {
feedViewButton.superview?.layoutIfNeeded()
}, completion: nil)
更新
如果您想稍后更改锚点上的常量以动画化其他更改,则必须保留对约束的引用以便以后能够操纵它们:
enum ConstraintType {
case top, leading, trailing, bottom, width, height
}
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> [ConstraintType : NSLayoutConstraint] {
//translate the view's autoresizing mask into Auto Layout constraints
translatesAutoresizingMaskIntoConstraints = false
var constraints: [ConstraintType : NSLayoutConstraint] = [:]
if let top = top {
constraints[.top] = topAnchor.constraint(equalTo: top, constant: padding.top)
}
if let leading = leading {
constraints[.leading] = leadingAnchor.constraint(equalTo: leading, constant: padding.left)
}
if let bottom = bottom {
constraints[.bottom] = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom)
}
if let trailing = trailing {
constraints[.trailing] = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right)
}
if size.width != 0 {
constraints[.width] = widthAnchor.constraint(equalToConstant: size.width)
}
if size.height != 0 {
constraints[.height] = heightAnchor.constraint(equalToConstant: size.height)
}
let constraintsArray = Array<NSLayoutConstraint>(constraints.values)
NSLayoutConstraint.activate(constraintsArray)
return constraints
}
}
此扩展 returns 一个约束字典,您可以稍后更改这些约束并为这些更改设置动画。例如:
let constraints = feedViewButton.anchor(top: nil, leading: nil, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 25), size: .init(width: 50, height: 50))
// applies the constraints
self.view.layoutIfNeeded()
// now to animate bottom to -50:
if let bottomConstraint = constraints[.bottom] {
bottomConstraint.constant = -50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
self.view.layoutIfNeeded()
})
animator.startAnimation()
}
您可以简单地在扩展上添加动画,因此所有对 anchor
的调用都将在不添加动画块的情况下进行动画处理。
extension UIView {
func anchor(animated: Bool, top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {
//translate the view's autoresizing mask into Auto Layout constraints
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
}
if let trailing = trailing {
trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
}
if size.width != 0 {
widthAnchor.constraint(equalToConstant: size.width).isActive = true
}
if size.height != 0 {
heightAnchor.constraint(equalToConstant: size.height).isActive = true
}
if animated {
UIView.animate(withDuration: 0.2, delay: 0, options: [.allowUserInteraction], animations: {
self.layoutIfNeeded()
}, completion: nil)
} else {
self.layoutIfNeeded()
}
}
}