UITableView+AutoLayout+内部大小:何时何地计算大小



我创建了一个自定义视图MyIntrincView,它在设置内容时自动计算其高度。这在模拟器和界面生成器中都能很好地工作。

但是,当将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 * someProperty20 * indexPath.row(。但是,所有单元格都具有相同的初始高度。

只有当显式调用myIntrinsicView.layoutSubviews()时,才会创建具有正确高度的单元格。

tableView似乎没有调用myIntrinsicView.layoutSubviews()为什么

当使用MyIntrinsicViewUILabelinstad作为具有不同文本长度的单元格内容时,一切都如预期的那样工作。因此,整个tableView设置是正确的(=单元格大小是自动计算的(,并且必须有办法在UITableView中正确使用内部大小那么,正确的方法是什么呢

与您之前的问题一样,我认为您并没有真正理解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-您张贴的代码显示您正在呼叫myIntrinsicView.layoutSubviews()。。。来自苹果的文档:

您不应该直接调用此方法。如果要强制更新布局,请在下一次图形更新之前调用setNeedsLayout方法。如果要立即更新视图的布局,请调用layoutIfNeeded方法。

2-对于它看起来像是你前进的方向,你可能最好操纵约束常数,而不是内在的内容大小。

最新更新