UILabel preferredMaxLayout 打破了自我调整大小的单元格

Posted

技术标签:

【中文标题】UILabel preferredMaxLayout 打破了自我调整大小的单元格【英文标题】:UILabel preferredMaxLayout breaking self-sizing cells 【发布时间】:2017-05-23 12:42:00 【问题描述】:

我发现 UILabel 无法与 AutoLayout 一起使用的一些非常烦人的问题。

我发现了多个关于此的线程,但没有一个解决方案适合我。

class AudiosHeaderCell: CollectionViewCell<AudiosHeaderItemViewModel> 
    var label: UILabelPreferedWidth? 
        didSet 
            self.label?.textAlignment = .center
            self.label?.numberOfLines = 0
            self.label?.lineBreakMode = .byWordWrapping
            self.label?.font = Font.Standard.size14
            self.label?.textColor = UIColor(netHex: 0x185B97)
        
    
    let labelLeftRightMargin = CGFloat(16)

    override func setupViews() 
        self.backgroundColor = UIColor.white

        self.label = UILabelPreferedWidth()
        self.contentView.addSubview(self.label!)
    

    override func setupConstraints() 
        self.label?.snp.makeConstraints  (make) in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 8, left: labelLeftRightMargin, bottom: 8, right: labelLeftRightMargin))
        
    

    override func bindViewModel(viewModel: AudiosHeaderItemViewModel) 
        self.label?.text = viewModel.text
    


class UILabelPreferedWidth : UILabel 
    override var bounds: CGRect 
        didSet 
            print("SET BOUNDS", bounds)
            if (bounds.size.width != oldValue.size.width) 
                self.setNeedsUpdateConstraints()
            
        
    

    override func updateConstraints() 
        print("updateConstraints", preferredMaxLayoutWidth, bounds)
        if(preferredMaxLayoutWidth != bounds.size.width) 
            preferredMaxLayoutWidth = bounds.size.width
        
        super.updateConstraints()
    

我使用一种方法来计算单元格的大小,如下所示:

func sizeForCellWithViewModel(_ viewModel: IReusableViewModel, fittingSize: CGSize) -> CGSize 
    let cell = self.classRegistry.instances[viewModel.reuseIdentifier]!
    (cell as! ICollectionViewCell).setViewModel(viewModel)
    cell.translatesAutoresizingMaskIntoConstraints = false
    cell.contentView.translatesAutoresizingMaskIntoConstraints = false
    cell.frame = CGRect(x: 0, y: 0, width: fittingSize.width, height: fittingSize.height)
    cell.setNeedsLayout()
    cell.layoutIfNeeded()

    print("SIZE FOR ", cell, "FITTING ", fittingSize, "IS", cell.systemLayoutSizeFitting(fittingSize))

    return cell.systemLayoutSizeFitting(fittingSize)

它适用于具有一些图像和其他内容的多个单元格,但在缩放到 UILabel 内容这样简单的问题上却失败了。

我遇到的问题是systemLayoutSizeFitting.width 返回的大小大于我传递的fittingSize.width 参数。

我已经调试了很长时间,我发现preferredMaxLayoutWidth 没有正确更新,因为这个 UILabel 的边界超出了单元格框架 - 尽管我在那里使用了约束。

有人对此有好的解决方案吗?

我发现的唯一一个是在 CollectionViewCell 上使用它:

override var frame: CGRect 
    didSet 
        self.label?.preferredMaxLayoutWidth = self.frame.size.width - 32
    

但我讨厌它,因为它迫使我将其与约束同步,并且我的应用程序中的所有其他用例都需要记住复制它。 我正在寻找的是 AutoLayout,只有约束的解决方案。

【问题讨论】:

你使用了自动布局吗? 是的,通过 SnapKit,您可以在代码中看到 【参考方案1】:

通过向 Cell 的 contentView 添加宽度约束解决了问题:

func sizeForCellWithViewModel(_ viewModel: IReusableViewModel, fittingSize: CGSize) -> CGSize 
    let cell = self.classRegistry.instances[viewModel.reuseIdentifier]!
    (cell as! ICollectionViewCell).setViewModel(viewModel)
    cell.contentView.frame = CGRect(x: 0, y: 0, width: fittingSize.width, height: fittingSize.height)
    cell.contentView.snp.removeConstraints()
    if fittingSize.width != 0 
        cell.contentView.snp.makeConstraints  (make) in
            make.width.lessThanOrEqualTo(fittingSize.width)
        
    
    if fittingSize.height != 0 
        cell.contentView.snp.makeConstraints( (make) in
            make.height.lessThanOrEqualTo(fittingSize.height)
        )
    
    cell.contentView.setNeedsLayout()
    cell.contentView.layoutIfNeeded()
    return cell.contentView.systemLayoutSizeFitting(fittingSize)

似乎这以某种方式使 UILabel 工作,并且 preferredWidth 不会发疯。

【讨论】:

以上是关于UILabel preferredMaxLayout 打破了自我调整大小的单元格的主要内容,如果未能解决你的问题,请参考以下文章

UIAlertController 或 UITextField 中的 UILabel 类似 UILabel

UILabel

ios6--UILabel

如何调整 UIView 的大小以获取大量 UILabel 并调整 UILabel 的大小以适合文本?

自动调整 UILabel 文本大小以适应 UILabel 宽度

IOS开发调整UILabel的行间距