如何计算动态类型的估计行高度

Posted

技术标签:

【中文标题】如何计算动态类型的估计行高度【英文标题】:How to calculate estimatedRowHeight for Dynamic Type 【发布时间】:2016-12-28 06:06:11 【问题描述】:

我有一个UITableViewController 的自定义子类。它有一个包含许多行的部分。每行对应于相同的自定义表格视图单元格类。每个自定义单元格都有两个标签:myLabel1myLabel2,这两个标签都是单元格 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)
    

【讨论】:

以上是关于如何计算动态类型的估计行高度的主要内容,如果未能解决你的问题,请参考以下文章

GWT StackLayoutPanel:动态和自动高度

UITableViewCell 高度根据行内容使用自动布局动态计算

如何在 CSS Grid 设置中考虑动态行?

带有 UIStackViews 的动态 UITableView 单元格高度

iOS两行代码实现动态缓存 cell 的高度

使用jquery动态添加表格的行之后,如何获取表格高度?