将UITabBarController添加到UIView时出现约束冲突警告
我通过代码将UITabBarController添加到UIView中,尽管模拟器里所有元素的布局都符合预期,但控制台出现了无法理解且无法消除的警告。
代码示例
final class MainController: UIViewController { let searchArea = SearchArea() let tabBarContainer = UIView() let tabBarControl = TabBarController() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground let safeArea = view.safeAreaLayoutGuide view.addSubview(searchArea) searchArea.backgroundColor = .systemBackground searchArea.addConstraints( .alignTopWithTop(of: safeArea), .alignLeadingWithLeading(of: safeArea), .alignTrailingWithTrailing(of: safeArea), .alignHeight(with: safeArea, mult: 0.05) ) searchArea.setupView() view.addSubview(tabBarContainer) tabBarContainer.backgroundColor = .systemBackground tabBarContainer.addConstraints( .alignTopWithBottom(of: searchArea), .alignLeadingWithLeading(of: safeArea), .alignTrailingWithTrailing(of: safeArea), .alignBottomWithBottom(of: safeArea) ) tabBarControl.view.frame = tabBarContainer.bounds tabBarControl.tabBar.backgroundColor = .systemBackground tabBarContainer.addSubview(tabBarControl.view) addChild(tabBarControl) tabBarControl.didMove(toParent: self) } }
控制台警告输出
2023-06-12 17:55:46.716982+0300 BFB[66775:3057149] [LayoutConstraints]
Unable to simultaneously satisfy constraints. Probably at least one
of the constraints in the following list is one you don't want. Try
this: (1) look at each constraint and try to figure out which you
don't expect; (2) find the code that added the unwanted constraint
or constraints and fix it. (Note: If you're seeing
NSAutoresizingMaskLayoutConstraints that you don't understand, refer
to the documentation for the UIView property
translatesAutoresizingMaskIntoConstraints) (
"<NSAutoresizingMaskLayoutConstraint:0x600003fe7340 h=-&- v=--& UINavigationBar:0x12f21ecd0.minY == 0 (active, names:
'|':UILayoutContainerView:0x12f21eb30 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003ff1e00 h=-&- v=--& UINavigationBar:0x12f21ecd0.height == 44 (active)>",
"<NSLayoutConstraint:0x600003fef110 V:[UINavigationBar:0x12f21ecd0]-(0)-[UIFocusContainerGuide:0x6000023f4870'UINavigationControllerContentFocusContainerGuide']
(active)>",
"<NSLayoutConstraint:0x600003feee40 UIFocusContainerGuide:0x6000023f4870'UINavigationControllerContentFocusContainerGuide'.bottom
== UILayoutContainerView:0x12f21eb30.bottom (active)>",
"<NSLayoutConstraint:0x600003f902d0 'UIView-Encapsulated-Layout-Height'
UILayoutContainerView:0x12f21eb30.height == 0 (active)>" )Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003fef110
V:[UINavigationBar:0x12f21ecd0]-(0)-[UIFocusContainerGuide:0x6000023f4870'UINavigationControllerContentFocusContainerGuide']
(active)>Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
to catch this in the debugger. The methods in the
UIConstraintBasedLayoutDebugging category on UIView listed in
<UIKitCore/UIView.h> may also be helpful.
我并未对UITabBarController自动创建的UINavigationBar做任何操作,警告在执行tabBarContainer.addSubview(tabBarControl.view)时出现。我试过设置translatesAutoresizingMaskIntoConstraints为false,也把自定义约束优先级设为.defaultLow,都无法解决问题。
问题出在你给tabBarControl.view设置frame的方式——仅设置初始frame无法保证布局更新时的尺寸稳定性,导致子控制器内部布局出现约束冲突。正确的做法是用Auto Layout约束让它完全填充容器视图。
修改步骤
- 移除
tabBarControl.view.frame = tabBarContainer.bounds这行代码 - 禁用
tabBarControl.view的自动调整掩码转换,添加约束让它填满tabBarContainer
修改后的代码片段:
// 替换原有的frame设置和子视图添加逻辑 tabBarControl.view.translatesAutoresizingMaskIntoConstraints = false tabBarContainer.addSubview(tabBarControl.view) addChild(tabBarControl) tabBarControl.didMove(toParent: self) // 添加约束固定tabBarControl.view的尺寸 NSLayoutConstraint.activate([ tabBarControl.view.topAnchor.constraint(equalTo: tabBarContainer.topAnchor), tabBarControl.view.leadingAnchor.constraint(equalTo: tabBarContainer.leadingAnchor), tabBarControl.view.trailingAnchor.constraint(equalTo: tabBarContainer.trailingAnchor), tabBarControl.view.bottomAnchor.constraint(equalTo: tabBarContainer.bottomAnchor) ])
原因说明
警告里的UILayoutContainerView:0x12f21eb30.height == 0表明UITabBarController的根视图在布局更新时被计算为高度0——这是因为你只设置了初始frame,没有用Auto Layout固定尺寸,系统更新布局时会重置这个frame。此时内部的UINavigationBar需要44的高度,而容器视图高度为0,自然触发约束冲突。
用Auto Layout约束子控制器视图的尺寸后,系统会正确计算容器视图的高度,内部导航栏和其他元素的约束也能正常生效,警告就会消失。
内容的提问来源于stack exchange,提问作者Alexey_BH

