问题描述
我创建了一个自定义视图 MyIntrincView
,它会在设置其内容时自动计算其高度。这在模拟器和 InterfaceBuilder 中都可以正常工作。
但是,当将 MyIntrinsicView
放在 UITableViewCell
中时,单元格高度没有正确计算。所有单元格都保持相同的初始高度,而不是自动采用单元格高度到视图的固有高度。
// A simple,custom view with intrinsic height. The height depends on
// the value of someProperty. When the property is changed setNeedsLayout
// is set and the height changes automatically.
@IBDesignable class MyIntrinsicView: UIView {
@IBInspectable public var someProperty: Int = 5 {
didSet { setNeedsLayout() }
}
override func layoutSubviews() {
super.layoutSubviews()
calcContent()
}
func calcContent() {
height = CGFloat(20 * someProperty)
invalidateIntrinsicContentSize()
}
@IBInspectable var height: CGFloat = 50
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width,height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
invalidateIntrinsicContentSize()
}
}
// A simple cell which only contains a MyIntrinsicView subview. The view
// is attached to trailing,leading,top and bottom anchors of the cell.
// Thus the cell height should automatically match the height of the
// MyIntrinsicView
class MyIntrinsicCell: UITableViewCell {
@IBOutlet private var myIntrinsicView: MyIntrinsicView!
var someProperty: Int {
get { return myIntrinsicView.someProperty }
set {
myIntrinsicView.someProperty = newValue
// Cell DOES NOT rezise without manualle calling layoutSubviews()
myIntrinsicView.layoutSubviews()
}
}
}
...
// Simple tableView delegate which should create cells of different heights
// by giving each cell a different someProperty
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "IntrinsicCell",for: indexPath) as? MyIntrinsicCell ?? MyIntrinsicCell()
// Give all cell a different intrinsic height by setting someProperty to rowIndex
cell.someProperty = indexPath.row
return cell
}
我希望每个单元格都有不同的高度 (20 * someProperty
= 20 * indexPath.row
)。但是,所有单元格都具有相同的初始高度。
仅当显式调用 myIntrinsicView.layoutSubviews()
时,单元格才会以正确的高度创建。
tableView 似乎没有调用 myIntrinsicView.layoutSubviews()
。 这是为什么?
当使用 UILabel
的 MyIntrinsicView
instad 作为具有不同文本长度的单元格内容时,一切都按预期工作。因此整个 tableView 设置是正确的(= 单元格大小是自动计算的)并且必须有方法在 UITableView
中正确使用固有大小。 那么,正确的做法是什么?
解决方法
与您之前的问题 here 一样,我认为您并没有真正了解 intrinsicContentSize
做什么和不做什么。
当设置 UILabel
的文本时,是的,它的 intrinsicContentSize
会发生变化,但这并不是全部。
您也不想在 layoutSubviews()
中执行您正在尝试的操作……如果您的代码确实触发了更改,您将进入无限递归循环(再次,就像你之前的问题一样)。
查看对代码的修改:
// A simple,custom view with intrinsic height. The height depends on
// the value of someProperty. When the property is changed setNeedsLayout
// is set and the height changes automatically.
@IBDesignable class MyIntrinsicView: UIView {
@IBInspectable public var someProperty: Int = 5 {
didSet {
calcContent()
setNeedsLayout()
}
}
func calcContent() {
height = CGFloat(20 * someProperty)
invalidateIntrinsicContentSize()
}
@IBInspectable var height: CGFloat = 50
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width,height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
invalidateIntrinsicContentSize()
}
}
// A simple cell which only contains a MyIntrinsicView subview. The view
// is attached to trailing,leading,top and bottom anchors of the cell.
// Thus the cell height should automatically match the height of the
// MyIntrinsicView
class MyIntrinsicCell: UITableViewCell {
@IBOutlet private var myIntrinsicView: MyIntrinsicView!
var someProperty: Int {
get { return myIntrinsicView.someProperty }
set {
myIntrinsicView.someProperty = newValue
}
}
}
两个旁注...
1 - 您发布的代码显示您从 Apple 的文档中调用 myIntrinsicView.layoutSubviews()
...:
你不应该直接调用这个方法。如果要强制更新布局,请在下一次绘图更新之前调用 setNeedsLayout 方法。如果您想立即更新视图的布局,请调用 layoutIfNeeded 方法。
2 - 对于看起来你前进的方向,你可能最好操纵约束常数,而不是内在的内容大小。