我有一个高度可变的单元格,在 Interface Builder ( )UITableView
中使用自动布局进行布局。rowHeight = UITableViewAutomaticDimension
当用户旋转设备时,我会在单元格内执行一些手动布局更改,这些更改会影响intrinsicContentSize
单元格的子视图之一。由于这些更改取决于该特定子视图的初始框架,因此我只能在布局引擎解决约束并将正确的框架应用于新(旋转)布局的所有子视图后应用这些更改。这发生在layoutSubviews()
方法内部。因此,要应用我的手动更改,我会覆盖该方法并首先调用超级实现。
override func layoutSubviews() {
// Call `super` implementation to let the layout engine do its job
// and apply the new frames to subviews after resolving constraints.
super.layoutSubviews()
// Apply manual layout changes here
}
现在的问题是我的手动布局更改可能还会更改单元格的高度。因此,我需要一种方法来通知表格视图,在(自动)高度计算返回之前,此单元格需要第二次布局传递。(否则表格视图将只使用它在手动布局更改之前计算的行高。)
通常,您通过setNeedsLayout()
调用需要另一个布局传递的视图来使布局无效来做到这一点。但是,我不能从layoutSubviews()
方法内部执行此操作,因为它会导致布局传递的无限循环并使应用程序崩溃。
所以我试图找出一种方法,如果布局在这个特定的调用中发生了变化,layoutSubviews()
并提出了这种方法:
override func layoutSubviews() {
// Get old image view size before layout pass
let previousImageSize = imageView.frame.size
// Run a layout pass
super.layoutSubviews()
// Get the new image view size
let newImageSize = imageView.frame.size
// Only trigger a new layout pass if the size changed
if newImageSize != previousImageSize {
// Apply manual layout changes here
// Trigger another layout pass
setNeedsLayout()
}
}
(在本例中,这imageView
是我的布局所依赖的单元格的子视图。)
运行这段代码时,我意识到if
分支内的代码永远不会执行,即方法imageView
内的大小永远不会改变layoutSubviews()
。但它确实改变了——只是在不同的时间。
这与我对自动布局的理解不一致:
视图始终负责布置其子视图,即适当地设置它们的框架,这是在
layoutSubviews()
.
所以这是我的问题:
- 为什么系统会从方法外部更改图像视图的大小
layoutSubviews()
?
更重要的是:
- 在计算单元格的行高时,如何让表格视图运行第二次布局传递?