动画约束时高度锚点的自动布局错误
Autolayout error on height anchor when animation constraints
我需要在我的应用程序的页脚呈现 UIView
,当用户执行某种操作时,该视图会滚动到视图的顶部并固定到位。
想象一下几乎一个标签栏视图动画化到一个导航栏中。
我基本上通过为我的视图设置 2 个锚点(顶部和底部)来模拟这一点。
然后我切换这些锚点并使用 UIView.animate
和 layoutIfNeeded
移动位置。
我的组件的内容然后锚定到父级的安全区域,这意味着我避免了 X 系列上的顶部和底部问题。
然而,当我的视图开始动画时,我的终端出现自动布局错误
(
"<NSLayoutConstraint:0x600002e38ff0 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.height == 44 (active)>",
"<NSLayoutConstraint:0x600002e38d70 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.top == UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'.top (active)>",
"<NSLayoutConstraint:0x600002e38e10 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.bottom == UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'.bottom (active)>",
"<NSLayoutConstraint:0x600002e39130 UIView:0x7fe64bc166b0.bottom == Home.AnimatedCustomNavigationView:0x7fe64bc02970.bottom (active)>",
"<NSLayoutConstraint:0x600002e390e0 V:|-(0)-[UIView:0x7fe64bc166b0] (active, names: '|':Home.AnimatedCustomNavigationView:0x7fe64bc02970 )>",
"<NSLayoutConstraint:0x600002e41810 'UIView-Encapsulated-Layout-Height' Home.AnimatedCustomNavigationView:0x7fe64bc02970.height == 896 (active)>",
"<NSLayoutConstraint:0x600002e38cd0 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide']-(34)-| (active, names: '|':UIView:0x7fe64bc166b0 )>",
"<NSLayoutConstraint:0x600002e38c30 'UIViewSafeAreaLayoutGuide-top' V:|-(0)-[UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'] (active, names: '|':UIView:0x7fe64bc166b0 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600002e38ff0 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.height == 44 (active)>
这似乎是由高度锚点引起的。
我不确定如何实现此效果并修复此错误。
import UIKit
class AnimatedCustomNavigationView: UIView {
private lazy var navBar = UIView(frame: .zero)
private var navBarTopAnchor: NSLayoutConstraint!
private var navBarBottomAnchor: NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = theme.color(.background)
navBar.backgroundColor = .purple
let label = UILabel(frame: .zero)
label.text = "Foo Bar Boo Baz"
label.sizeToFit()
addSubview(navBar)
navBar.addSubview(label)
[navBar, label].forEach { [=11=].translatesAutoresizingMaskIntoConstraints = false }
NSLayoutConstraint.activate([
// MARK: - NavBar Container
navBar.leadingAnchor.constraint(equalTo: self.leadingAnchor),
navBar.trailingAnchor.constraint(equalTo: self.trailingAnchor),
// MARK: - Label
label.topAnchor.constraint(equalTo: navBar.safeAreaLayoutGuide.topAnchor),
label.leadingAnchor.constraint(equalTo: navBar.leadingAnchor, constant: 16),
label.bottomAnchor.constraint(equalTo: navBar.safeAreaLayoutGuide.bottomAnchor),
label.trailingAnchor.constraint(equalTo: navBar.trailingAnchor, constant: -16),
label.heightAnchor.constraint(equalToConstant: 44)
])
navBarTopAnchor = navBar.topAnchor.constraint(equalTo: topAnchor)
navBarTopAnchor.isActive = false
navBarBottomAnchor = navBar.bottomAnchor.constraint(equalTo: bottomAnchor)
navBarBottomAnchor.isActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.navBarTopAnchor.isActive = true
self.navBarBottomAnchor.isActive = false
UIView.animate(withDuration: 1.5, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
}
}
required init?(coder aDecoder: NSCoder) {
return nil
}
}
现在为了模拟用户操作,我将动画调用包装在 DispatchQueue.main.asyncAfter
您需要正确排序 .isActive = false
应该在 .isActive = true
之前
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.navBarBottomAnchor.isActive = false
self.navBarTopAnchor.isActive = true
UIView.animate(withDuration: 1.5, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
}
我需要在我的应用程序的页脚呈现 UIView
,当用户执行某种操作时,该视图会滚动到视图的顶部并固定到位。
想象一下几乎一个标签栏视图动画化到一个导航栏中。
我基本上通过为我的视图设置 2 个锚点(顶部和底部)来模拟这一点。
然后我切换这些锚点并使用 UIView.animate
和 layoutIfNeeded
移动位置。
我的组件的内容然后锚定到父级的安全区域,这意味着我避免了 X 系列上的顶部和底部问题。
然而,当我的视图开始动画时,我的终端出现自动布局错误
(
"<NSLayoutConstraint:0x600002e38ff0 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.height == 44 (active)>",
"<NSLayoutConstraint:0x600002e38d70 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.top == UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'.top (active)>",
"<NSLayoutConstraint:0x600002e38e10 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.bottom == UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'.bottom (active)>",
"<NSLayoutConstraint:0x600002e39130 UIView:0x7fe64bc166b0.bottom == Home.AnimatedCustomNavigationView:0x7fe64bc02970.bottom (active)>",
"<NSLayoutConstraint:0x600002e390e0 V:|-(0)-[UIView:0x7fe64bc166b0] (active, names: '|':Home.AnimatedCustomNavigationView:0x7fe64bc02970 )>",
"<NSLayoutConstraint:0x600002e41810 'UIView-Encapsulated-Layout-Height' Home.AnimatedCustomNavigationView:0x7fe64bc02970.height == 896 (active)>",
"<NSLayoutConstraint:0x600002e38cd0 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide']-(34)-| (active, names: '|':UIView:0x7fe64bc166b0 )>",
"<NSLayoutConstraint:0x600002e38c30 'UIViewSafeAreaLayoutGuide-top' V:|-(0)-[UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'] (active, names: '|':UIView:0x7fe64bc166b0 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600002e38ff0 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.height == 44 (active)>
这似乎是由高度锚点引起的。
我不确定如何实现此效果并修复此错误。
import UIKit
class AnimatedCustomNavigationView: UIView {
private lazy var navBar = UIView(frame: .zero)
private var navBarTopAnchor: NSLayoutConstraint!
private var navBarBottomAnchor: NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = theme.color(.background)
navBar.backgroundColor = .purple
let label = UILabel(frame: .zero)
label.text = "Foo Bar Boo Baz"
label.sizeToFit()
addSubview(navBar)
navBar.addSubview(label)
[navBar, label].forEach { [=11=].translatesAutoresizingMaskIntoConstraints = false }
NSLayoutConstraint.activate([
// MARK: - NavBar Container
navBar.leadingAnchor.constraint(equalTo: self.leadingAnchor),
navBar.trailingAnchor.constraint(equalTo: self.trailingAnchor),
// MARK: - Label
label.topAnchor.constraint(equalTo: navBar.safeAreaLayoutGuide.topAnchor),
label.leadingAnchor.constraint(equalTo: navBar.leadingAnchor, constant: 16),
label.bottomAnchor.constraint(equalTo: navBar.safeAreaLayoutGuide.bottomAnchor),
label.trailingAnchor.constraint(equalTo: navBar.trailingAnchor, constant: -16),
label.heightAnchor.constraint(equalToConstant: 44)
])
navBarTopAnchor = navBar.topAnchor.constraint(equalTo: topAnchor)
navBarTopAnchor.isActive = false
navBarBottomAnchor = navBar.bottomAnchor.constraint(equalTo: bottomAnchor)
navBarBottomAnchor.isActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.navBarTopAnchor.isActive = true
self.navBarBottomAnchor.isActive = false
UIView.animate(withDuration: 1.5, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
}
}
required init?(coder aDecoder: NSCoder) {
return nil
}
}
现在为了模拟用户操作,我将动画调用包装在 DispatchQueue.main.asyncAfter
您需要正确排序 .isActive = false
应该在 .isActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.navBarBottomAnchor.isActive = false
self.navBarTopAnchor.isActive = true
UIView.animate(withDuration: 1.5, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
}