如何计算动态类型的估计行高度
Posted
技术标签:
【中文标题】如何计算动态类型的估计行高度【英文标题】:How to calculate estimatedRowHeight for Dynamic Type 【发布时间】:2016-12-28 06:06:11 【问题描述】:我有一个UITableViewController
的自定义子类。它有一个包含许多行的部分。每行对应于相同的自定义表格视图单元格类。每个自定义单元格都有两个标签:myLabel1
和 myLabel2
,这两个标签都是单元格 contentView
的子视图。
每个myLabel1
有一行文字,每个myLabel2
有一两行文字,但每个单元格应该有相同的高度,就好像每个myLabel2
有两行文字一样。
标签使用动态类型。
myLabel1.font = UIFont.preferredFont(forTextStyle: .headline)
myLabel2.font = UIFont.preferredFont(forTextStyle: .subheadline)
根据Working with Self-Sizing Table View Cells,我已将每个标签定位为自动布局,并“将表格视图的rowHeight
属性设置为UITableViewAutomaticDimension
”,以便行高随动态类型而变化。
如何使每个单元格都具有相同的高度?
我应该如何估计表格视图的行高?
【问题讨论】:
这取决于单元格的内容。使用自定尺寸您无法控制尺寸。您必须设置相同的内容。或者如果您想要相同的尺寸,请不要使用自选尺寸。 创建一个使 label2 的高度等于 label1 的约束。 基本上UITableView
的每个单元格都应具有UITableView
的任何一个单元格在运行时可能具有的最大高度?
移除 UITableViewAutomaticDimension 以修复大小。并使用 tableView 委托方法来指定修复或计算的行高。
我希望每个单元格都具有相同的高度,并且该高度应根据每个用户的Dynamic Type 设置而改变。 “动态类型通过让读者选择他们喜欢的文本大小来提供额外的灵活性。”
【参考方案1】:
UITableViewAutomaticDimension
将根据单元格内容大小估计单元格大小。我们必须计算一个单元格可能具有的最大高度,并为所有单元格返回这个高度,而不是使用UITableViewAutomaticDimension
。
CustomTableViewCell
let kMargin: CGFloat = 8.0
class CustomTableViewCell: UITableViewCell
@IBOutlet var singleLineLabel: UILabel!
@IBOutlet var doubleLineLabel: UILabel!
override func awakeFromNib()
super.awakeFromNib()
// Initialization code
updateFonts()
override func prepareForReuse()
updateFonts()
func updateFonts()
singleLineLabel.font = UIFont.preferredFont(forTextStyle:.title3)
doubleLineLabel.font = UIFont.preferredFont(forTextStyle:.body)
func updateCellForCellWidth(_ width:CGFloat)
doubleLineLabel.preferredMaxLayoutWidth = width - (2*kMargin)
func fillCellWith(_ firstString: String, _ secondString: String)
singleLineLabel.text = firstString
doubleLineLabel.text = secondString
在视图控制器上
设置一个虚拟单元格并列出动态类型的通知
var heightCalculatorDummyCell: CustomTableViewCell!
var maxHeight: CGFloat = 0.0
override func viewDidLoad()
super.viewDidLoad()
heightCalculatorDummyCell = tableView.dequeueReusableCell(withIdentifier: "cell_id") as! CustomTableViewCell
maxHeight = getMaxHeight()
NotificationCenter.default.addObserver(self, selector: #selector(AutomaticHeightTableViewController.didChangePreferredContentSize), name: .UIContentSizeCategoryDidChange, object:nil)
使用虚拟单元获得最大高度。
func getMaxHeight() -> CGFloat
heightCalculatorDummyCell.updateFonts()
heightCalculatorDummyCell.fillCellWith("Title","A string that needs more than two lines. A string that needs more than two lines. A string that needs more than two lines. A string that needs more than two lines. A string that needs more than two lines.")
heightCalculatorDummyCell.updateCellForCellWidth(tableView.frame.size.width)
let size = heightCalculatorDummyCell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
return (size.height + 1)
处理表格视图在通知时重新加载
deinit
NotificationCenter.default.removeObserver(self)
func didChangePreferredContentSize()
maxHeight = getMaxHeight()
tableView.reloadData()
最后一步,在 tableview 委托中返回最大高度
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return titles.count
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
return maxHeight
【讨论】:
哇,好答案!谢谢你。顺便说一句,需要两行的刺痛可以简单地是:"\n"
。【参考方案2】:
将myLabel2
设为FixedHeightLabel
,使其高度始终为两行。
class FixedHeightLabel: TopAlignedLabel
override var intrinsicContentSize: CGSize
let oldText = text
text = "\n"
let height = sizeThatFits(CGSize(width: .max, height: .max)).height
text = oldText
return CGSize(width: UIViewNoIntrinsicMetric, height: height)
class TopAlignedLabel: UILabel
override func drawText(in rect: CGRect)
let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
super.drawText(in: textRect)
【讨论】:
以上是关于如何计算动态类型的估计行高度的主要内容,如果未能解决你的问题,请参考以下文章
UITableViewCell 高度根据行内容使用自动布局动态计算