UILabel首选MaxLayout打破自我大小的细胞

时间:2017-05-23 12:42:00

标签: swift autolayout uilabel constraints uicollectionviewcell

我发现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,仅限约束解决方案。

1 个答案:

答案 0 :(得分:0)

通过向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工作,而且首选宽度不会变得疯狂。