我发现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,仅限约束解决方案。
答案 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工作,而且首选宽度不会变得疯狂。