子视图控制器的视图忽略自动布局约束
Posted
技术标签:
【中文标题】子视图控制器的视图忽略自动布局约束【英文标题】:Child view controller's view ignores Auto Layout constraints 【发布时间】:2020-07-10 17:42:18 【问题描述】:我想将子视图控制器添加到UINavigationController's
视图。我有这样的层次结构
NavigationController
-> View(drawer
) -> View(contentContainer
) -> 子视图控制器应该固定到 contentContainer
但由于某种原因,它忽略了约束,我得到了奇怪的结果。请看截图,drawer
是绿色的,contentContainer
是黄色的,子控制器几乎放置在屏幕之外,并且框架高度为 0。
关键代码在 drawerContentController
didSet
和 setupView
方法中。请注意,我使用 SnapKit 进行约束,但通过传统方式设置 NSLayoutConstraints
会发生同样的问题
class NavigationController: UINavigationController
private var drawerHeightConstraint: Constraint!
fileprivate lazy var drawer = UIView()
private lazy var contentContainer = UIView()
var drawerContentController: UIViewController?
didSet
guard let new = drawerContentController else
oldValue?.removeFromParent(animated: true)
return
if let old = oldValue
old.removeFromParent(animated: true) _ in
self.add(child: new, superview: self.contentContainer, animated: true, completion: nil)
else
add(child: new, superview: contentContainer, animated: true, completion: nil)
override func viewDidLoad()
super.viewDidLoad()
setupView()
private func setupView()
view.addSubview(drawer)
drawer.backgroundColor = .green
drawer.snp.makeConstraints make in
make.leading.bottom.trailing.equalToSuperview()
drawerHeightConstraint = make.height.equalTo(360).constraint
let blur = UIBlurEffect(style: .default)
let visualView = UIVisualEffectView(effect: blur)
drawer.addSubview(visualView)
visualView.pinToSuperView()
contentContainer.backgroundColor = .yellow
drawer.addSubview(contentContainer)
contentContainer.snp.makeConstraints make in
make.edges.equalTo(drawer.safeAreaLayoutGuide)
func add(child controller: UIViewController, superview: UIView? = nil, animated: Bool, completion: ((Bool) -> Void)? = nil)
controller.willMove(toParent: self)
addChild(controller)
controller.view.alpha = 0
(superview ?? view).addSubview(controller.view)
controller.view.pinToSuperView()
UIView.animate(withDuration: animated ? 0.3 : 0, animations:
controller.view.alpha = 1
) finished in
controller.didMove(toParent: self)
completion?(finished)
extension UIView
func pinToSuperView()
snp.makeConstraints make in
make.edges.equalToSuperview()
当我向 contentContainer 添加一个简单的 UIView 时,它会按预期工作
var drawerContentController: UIViewController?
didSet
let v = UIView()
v.backgroundColor = .purple
contentContainer.addSubview(v)
v.pinToSuperView()
【问题讨论】:
看到感叹号了吗?这些是您正在犯的自动布局错误。你需要看看它们是什么。 它只是说视图的大小不明确。您是否看到在第二个屏幕截图中,在彩色视图下可以看到表格视图?虽然第一个根本没有控制器,但 UINavigationController 似乎不喜欢向其中添加子控制器。我会将导航控制器嵌入到其他控制器中,并将子视图添加到嵌入控制器中 我不知道你所说的“公正”是什么意思。歧义是您遇到问题的原因。 它不是,正如我在帖子中所说,使用相同约束添加和定位的简单 UIView 可以正常工作。 UINavigationController 似乎不允许添加子视图控制器 【参考方案1】:好的,我“解决”了这个问题。
似乎UINavigationController
不喜欢添加子视图控制器。如屏幕截图所示,当添加子控制器时,导航控制器的整个视图层次结构都被破坏了。在第二个屏幕截图中,表格视图控制器(白色视图)正确显示,但在第一种情况下,它甚至不在视图层次结构中!
所以道德是,尽量不要将子视图控制器直接添加到UINavigationController
,最终它不是一个正常的UIViewController
,甚至没有一个正常的UIView
。我添加了另一个UIViewController
作为UINavigationController
的容器,并将子控制器添加到其中。它现在按预期工作。
【讨论】:
一个 UINavigationController 确实有一个“普通的 UIView”。这里的问题仅仅是你没有考虑到 UINavigationController 已经 有孩子的事实,它以适合导航控制器的特殊方式对待它们:它们是推送到其堆栈上的视图控制器,简单明了。以上是关于子视图控制器的视图忽略自动布局约束的主要内容,如果未能解决你的问题,请参考以下文章
iOS:在 iOS 7 和 iOS 8 上将约束应用于子视图的自动布局差异