具有基于宽度的固有高度的 UITableViewCell
UITableViewCell with intrinsic height based on width
所以我制作了自定义视图 ExpressionView 来可视化数学表达式。 expression 的每一部分都是 UILabel,其中包含一个数字或操作,并且标签在 ExpressionView 内以右对齐的行对齐。我希望 ExpressionView 的宽度由外部的自动布局约束定义,但高度应该是固有的,具体取决于我必须为给定宽度制作多少行标签。
对齐方法效果很好,我使用每个标签的 frame.size 和 ExpressionView 的宽度,进行数学运算,设置标签的框架位置,并计算所需的高度以包含所有行。我还定义了这些,以便设置固有大小,并在每次 ExpressionLabel 宽度更改时重新布局标签:
override var intrinsicContentSize: CGSize {
let res = CGSize(width: UIView.noIntrinsicMetric,
height: CGFloat(self.contentHeight) //counted during self.layoutAllLabels()
)
return res
}
public override func layoutSubviews() {
super.layoutSubviews() //finish layout to get current label sizes and self width
let preHeight = self.contentHeight
self.layoutAllLabels() //layout all labels in current width, count required height
//if required height changed, relayout everything
if (preHeight != self.contentHeight) {
self.invalidateIntrinsicContentSize()
self.superview?.setNeedsLayout()
self.superview?.layoutIfNeeded()
}
}
当 ExpressionLabel 通过普通 UIView 中的自动布局约束设置到位时,一切正常。但是当 ExpressionLabel 固定在 UITableViewCell 的 contentView 中时它失败了,我希望它定义单元格的高度。我的 UITableView 具有自动调整单元格大小所需的这些行
self.estimatedRowHeight = 50
self.rowHeight = UITableView.automaticDimension
单个单元格的大小以某种方式发生并且通常是正确的,但通常也会给出无效的高度。它可能与单元格重用(通过 dequeueReusableCells())有关,因为旧高度可能保留在重用单元格中。但是为什么它们不更新,什么时候应该在任何 ExpressionView.layoutSubviews() 调用中更新?在 UITableView 中创建时,单元格是否不会自动布局?如果没有,在哪里布局我的标签,以便即使在 UITableView 中也能正确更新?当我知道最终的单元格宽度,并可以根据它调整其子视图的固有高度时?
知道了!似乎 autodimensioned UITableViewCell 的高度是通过调用 cell 的 systemLayoutSizeFitting()
从 UITableView 确定的。在我的单元格 class 中,我覆盖了该方法,并在调用 super.systemLayoutSizeFitting() 之前调用 layoutIfNeeded() - 以获得正确的尺寸。那行得通!也许我什至可以直接调用 ExpressionView 排列方法,而不是通过 layoutIfNeeded(),但我会保持原样。
这是我单元格中的覆盖 class:
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
//force layout of all subviews including ExpressionView, which
//updates ExpressionView's intrinsic height, and thus height of a cell
self.setNeedsLayout()
self.layoutIfNeeded()
//now intrinsic height is correct, so I can call super method
return super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority)
}
所以我制作了自定义视图 ExpressionView 来可视化数学表达式。 expression 的每一部分都是 UILabel,其中包含一个数字或操作,并且标签在 ExpressionView 内以右对齐的行对齐。我希望 ExpressionView 的宽度由外部的自动布局约束定义,但高度应该是固有的,具体取决于我必须为给定宽度制作多少行标签。
对齐方法效果很好,我使用每个标签的 frame.size 和 ExpressionView 的宽度,进行数学运算,设置标签的框架位置,并计算所需的高度以包含所有行。我还定义了这些,以便设置固有大小,并在每次 ExpressionLabel 宽度更改时重新布局标签:
override var intrinsicContentSize: CGSize {
let res = CGSize(width: UIView.noIntrinsicMetric,
height: CGFloat(self.contentHeight) //counted during self.layoutAllLabels()
)
return res
}
public override func layoutSubviews() {
super.layoutSubviews() //finish layout to get current label sizes and self width
let preHeight = self.contentHeight
self.layoutAllLabels() //layout all labels in current width, count required height
//if required height changed, relayout everything
if (preHeight != self.contentHeight) {
self.invalidateIntrinsicContentSize()
self.superview?.setNeedsLayout()
self.superview?.layoutIfNeeded()
}
}
当 ExpressionLabel 通过普通 UIView 中的自动布局约束设置到位时,一切正常。但是当 ExpressionLabel 固定在 UITableViewCell 的 contentView 中时它失败了,我希望它定义单元格的高度。我的 UITableView 具有自动调整单元格大小所需的这些行
self.estimatedRowHeight = 50
self.rowHeight = UITableView.automaticDimension
单个单元格的大小以某种方式发生并且通常是正确的,但通常也会给出无效的高度。它可能与单元格重用(通过 dequeueReusableCells())有关,因为旧高度可能保留在重用单元格中。但是为什么它们不更新,什么时候应该在任何 ExpressionView.layoutSubviews() 调用中更新?在 UITableView 中创建时,单元格是否不会自动布局?如果没有,在哪里布局我的标签,以便即使在 UITableView 中也能正确更新?当我知道最终的单元格宽度,并可以根据它调整其子视图的固有高度时?
知道了!似乎 autodimensioned UITableViewCell 的高度是通过调用 cell 的 systemLayoutSizeFitting()
从 UITableView 确定的。在我的单元格 class 中,我覆盖了该方法,并在调用 super.systemLayoutSizeFitting() 之前调用 layoutIfNeeded() - 以获得正确的尺寸。那行得通!也许我什至可以直接调用 ExpressionView 排列方法,而不是通过 layoutIfNeeded(),但我会保持原样。
这是我单元格中的覆盖 class:
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
//force layout of all subviews including ExpressionView, which
//updates ExpressionView's intrinsic height, and thus height of a cell
self.setNeedsLayout()
self.layoutIfNeeded()
//now intrinsic height is correct, so I can call super method
return super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority)
}