[英]Understanding Auto Layout lifecycle and sequence with embedded views
I have the following view hierarchy:我有以下视图层次结构:
ViewController: UIViewController
|
+--- cardViewController: CardViewController (subclass of UIViewController)
|
+--- containerView: UIView
|
+--- menuTableView: MenuTableView (subclass of UITableView)
The CardViewController
is shown on the ViewController
's view through the folloing code (called from ViewController): CardViewController
通过以下代码(从 ViewController 调用)显示在ViewController
的视图中:
let cardViewController = CardViewController(startWithRoundedCorners: true)
self.addChild(cardViewController)
self.view.addSubview(cardViewController.view)
cardViewController.showCard()
In CardViewController
, the containerView
has constraints to the view's top, leading, trailing, and bottom anchors.在CardViewController
中, containerView
对视图的顶部、前导、尾随和底部锚点有约束。
In turn, the menuTableView
also has constraints to the containerView
s top leading, trailing and bottom anchors.反过来, menuTableView
也对containerView
的顶部前导、尾随和底部锚点有约束。
The issue is this.问题是这样的。 The menuTableView.contentSize.height
is only being calculated after the tableView cells are loaded through cellForRowAt
. menuTableView.contentSize.height
仅在通过cellForRowAt
加载 tableView 单元格后计算。 Makes sense.说得通。 Up until that point in time, it looks like it's just doing an estimation of the tableView height based on the number of rows * 44 (the default size).直到那个时间点,它看起来只是根据行数 * 44(默认大小)来估计 tableView 的高度。 So if I check the menuTableView.contentSize.height
in CardViewController: viewDidLayoutSubviews()
, I get back 264.0
.因此,如果我检查menuTableView.contentSize.height
CardViewController: viewDidLayoutSubviews()
中的 menuTableView.contentSize.height ,我会返回264.0
。
I've captured some print statements (with a 'started' and 'finished' for some of the overridden methods) to try and work out the order that things are running in:我已经捕获了一些打印语句(对于一些被覆盖的方法有一个“开始”和“完成”)来尝试计算出事情运行的顺序:
CardViewController: setuptableView(): started
MenuTableView: convenience init(): started
MenuTableView: override init(): started
MenuTableView: numberOfRowsInSection:
MenuTableView: override init(): self.frame.height: 0.0
MenuTableView: override init(): self.contentSize.height: 0.0
MenuTableView: override init(): finished
MenuTableView: convenience init(): self.frame.height: 0.0
MenuTableView: convenience init(): self.contentSize.height: 0.0
MenuTableView: convenience init(): finished
CardViewController: setuptableView(): finished
MenuTableView: numberOfRowsInSection:
CardViewController: showCard(): self.frame.height: 0.0
CardViewController: showCard(): self.contentSize.height: 264.0
CardViewController: updateViewConstraints(): started
CardViewController: updateViewConstraints(): finished
CardViewController: viewWillLayoutSubviews(): started
CardViewController: viewDidLayoutSubviews(): self.frame.height: 0.0
CardViewController: viewDidLayoutSubviews(): self.contentSize.height: 264.0
CardViewController: viewWillLayoutSubviews(): finished
CardViewController: viewDidLayoutSubviews(): started
CardViewController: viewDidLayoutSubviews(): self.frame.height: 0.0
CardViewController: viewDidLayoutSubviews(): self.contentSize.height: 264.0
CardViewController: viewDidLayoutSubviews(): finished
MenuTableView: numberOfRowsInSection:
MenuTableView: layoutSubviews(): started
MenuTableView: numberOfRowsInSection:
MenuTableView: cellForRowAt indexPath: [0, 0]
MenuTableView: cellForRowAt indexPath: [0, 1]
MenuTableView: cellForRowAt indexPath: [0, 2]
MenuTableView: cellForRowAt indexPath: [0, 3]
MenuTableView: cellForRowAt indexPath: [0, 4]
MenuTableView: cellForRowAt indexPath: [0, 5]
MenuTableView: layoutSubviews(): self.frame.height: 264.0
MenuTableView: layoutSubviews(): self.contentSize.height: 306.0
MenuTableView: layoutSubviews(): finished
MenuTableView: layoutSubviews(): started
MenuTableView: layoutSubviews(): self.frame.height: 264.0
MenuTableView: layoutSubviews(): self.contentSize.height: 306.0
MenuTableView: layoutSubviews(): finished
The code for the CardViewController: showCard()
method is: CardViewController: showCard()
方法的代码是:
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
let cardHeight = (self?.menuTableView.contentSize.height)! + self!.cardHandleAreaHeight
self?.view.frame = CGRect(x: 0, y: (self?.parent?.view.frame.height)! - cardHeight, width: (self?.parent?.view.frame.width)!, height: cardHeight)
}, completion: nil)
So from what I can tell, the problem is that the menuTableView.layoutSubviews
gets called, and correctly has the tableView.contentSize.height
at 306.0
.所以据我所知,问题是menuTableView.layoutSubviews
被调用,并且tableView.contentSize.height
正确地位于306.0
。 But by this stage, the parent viewController ( CardViewController
) has already finished with its viewWillLayoutSubviews
and viewDidLayoutSubviews
.但是到了这个阶段,父 viewController ( CardViewController
) 已经完成了它的viewWillLayoutSubviews
和viewDidLayoutSubviews
。
Question问题
How can the parent be finished laying out its subviews when the subviews are actually still laying out their views??当子视图实际上仍在布置其视图时,父级如何完成其子视图的布置? Based on Apple's documentation, they say that the Auto Layout loop is:根据Apple的文档,他们说自动布局循环是:
And if changes to the intrinsic content size of, in this case, the tableView cause an update to occur to the auto layout constraints, I'm at a loss why this loop doesn't work.如果在这种情况下更改 tableView 的内在内容大小会导致自动布局约束发生更新,我不知道为什么这个循环不起作用。 I've played around with a whole bunch of options and there are different ways to trigger it but I'm looking to understand the Auto Layout engine so I stop running into these issues.我玩过一大堆选项,并且有不同的方法来触发它,但我希望了解自动布局引擎,所以我不再遇到这些问题。
Additional Info附加信息
Interesting, if I call cardViewController.showCard()
a second time, then it is correct.有趣的是,如果我再次调用cardViewController.showCard()
,那么它是正确的。 The additional print logs are then:额外的打印日志是:
CardViewController: showCard(): started
CardViewController: showCard(): self.frame.height: 278.0
CardViewController: showCard(): self.contentSize.height: 306.0
CardViewController: showCard(): finished
CardViewController: viewWillLayoutSubviews(): started
CardViewController: viewDidLayoutSubviews(): self.frame.height: 278.0
CardViewController: viewDidLayoutSubviews(): self.contentSize.height: 306.0
CardViewController: viewWillLayoutSubviews(): finished
CardViewController: viewDidLayoutSubviews(): started
CardViewController: viewDidLayoutSubviews(): self.frame.height: 278.0
CardViewController: viewDidLayoutSubviews(): self.contentSize.height: 306.0
CardViewController: viewDidLayoutSubviews(): finished
MenuTableView: layoutSubviews(): started
MenuTableView: layoutSubviews(): self.frame.height: 306.0
MenuTableView: layoutSubviews(): self.contentSize.height: 306.0
MenuTableView: layoutSubviews(): finished
Happy to make the project file available if that's easier.如果这更容易,很高兴使项目文件可用。
sorry i can't add a comment yet
so i tried to use this answer section
as question.抱歉,我还不能添加yet
所以我尝试将此answer section
用作问题。
where did you put these?你把这些放在哪里了?
let cardViewController = CardViewController(startWithRoundedCorners: true)
self.addChild(cardViewController)
self.view.addSubview(cardViewController.view)
cardViewController.showCard()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.