UICollectionViewCompositionalLayout 具有动态单元格高度的标签布局

问题描述 投票:0回答:1

我正在尝试实现这种标签布局(具有动态宽度和高度的集合视图单元格),但是当单元格内标签的文本很长时,代码会因一些约束错误而崩溃。有没有办法让标签具有多行文本和这种布局?如何将单元格的最大宽度限制为组的宽度尺寸并支持多行文本?另外,例如,如果第 3 项的标签(参见图片)将有两行文本,我希望该单元格环绕到第 2 行并占据第 2 行和第 3 行。然后第 4 项应该从第 4 行开始。

如果此布局无法在标签中包含多行文本,我如何将标签中的行数限制为 1,并将标签的宽度限制为组的宽度尺寸,即截断标签中的文本,如果它会在标签中占据不止一行吗?

func makeLayout() -> UICollectionViewLayout {
    let layout = UICollectionViewCompositionalLayout { (section: Int, environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in

        let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(100), heightDimension: .estimated(32))
        let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)

        let layoutGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: itemSize.heightDimension)
        let layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize, subitems: [layoutItem])

        layoutGroup.interItemSpacing = .fixed(8)

        let section = NSCollectionLayoutSection(group: layoutGroup)
        section.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
        section.interGroupSpacing = 8
            
        return section
    }
    return layout
}

uicollectionviewcell uicollectionviewcompositionallayout
1个回答
0
投票

在您的示例中,您的组大小为

.fractionalWidth(1)
- 这意味着它等于该部分的大小。您可以从容器宽度获取此值 - 该值来自初始化 UICollectionViewCompositionalLayout 时的
environment: NSCollectionLayoutEnvironment
参数。

所以你会在你的代码中做这样的事情:

let layout = UICollectionViewCompositionalLayout { (section: Int, environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
    //save this width information somewhere in your class
    let availableWidth: CGFloat = environment.container.effectiveContentSize.width
    ...
    ... //continue to configure your layout normally
}

在显示标签的单元格中,创建最大宽度约束。如果您使用 Interface Builder,请确保约束已连接到 IBOutlet。以下是如何在 Interface Builder 中实现此目的。如果您不使用 IB - 那么在您的代码中执行相同的操作。

当您使用文本配置单元格时,还要配置此最大宽度约束。也许你的 UICollectionViewDelegate 中有这样的东西:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let tagCell = collectionView.dequeueReusableCell(withReuseIdentifier: "tagCellIdentifier", for: indexPath) as? TagCell
    let tagData = backingDataSource[indexPath.item] //imagine there is an array named backingDataSource
    tagCell.configure(with: tagData, maxWidth: self.availableWidth)
    return tagCell
}

最后你的 TagCell 定义如下所示。如果您使用 SwiftUI,则需要将其转换为 SwiftUI。

class TagCell: UICollectionViewCell {
    @IBOutlet private weak var tagLabel: UILabel!
    @IBOutlet private weak var tagMaxWidthConstraint: NSLayoutConstraint!

    override func awakeFromNib() {
        super.awakeFromNib()
    
        tagLabel.numberOfLines = 2
        tagLabel.lineBreakMode = .byTruncatingTail
        //configure your label according to your needs
    }
    ...
    ...
    
    func configure(with tagData: String, maxWidth: CGFloat) {
        self.tagLabel.text = tagData
        self.tagMaxWidthConstraint.constant = maxWidth
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.