UICollectionViewCompositionalLayout Collectionview 重新加载数据后未正确调整单元格宽度

UICollectionViewCompositionalLayout Collectionview cell width not resizing properly after reloading data

提问人:caa5042 提问时间:11/5/2023 最后编辑:caa5042 更新时间:11/8/2023 访问量:42

问:

我正在使用 UICollectionViewCompositionalLayout 在我的 collectionview 的某些部分创建动态宽度、固定高度、标记单元格类型的布局。当我将新字符串添加到数据库中的数组中,将数组重新加载到我的数据源中并执行 collectionview reloaddata 时,单元格会以不可预测的方式调整大小。有时它们会正确调整大小以适应字符串的宽度,有时它们似乎使用单元格的估计宽度并截断字符串。关于如何解决这个问题的任何建议?我在下面发布了一个gif。

enter image description here

这是我的makelayout函数(简化并删除了不必要的代码行):

override func makeLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout(sectionProvider: { (sectionIndex, environment) -> NSCollectionLayoutSection? in


        let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(40), heightDimension: .absolute(40))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let inset: CGFloat = 10
        item.contentInsets = NSDirectionalEdgeInsets(top: inset, leading: inset, bottom: inset, trailing: inset)
            
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(40))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        group.interItemSpacing = NSCollectionLayoutSpacing.fixed(CGFloat(10))
        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = CGFloat(10.0)
        section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
        section.supplementariesFollowContentInsets = false

        return section
          
    })
        
        
    let config = UICollectionViewCompositionalLayoutConfiguration()
    config.scrollDirection = .vertical
    config.interSectionSpacing = 10
    layout.configuration = config
      
    return layout
}

这是我的自定义 CollectionViewCell

class CollectionViewCell: UICollectionViewCell {
    
    lazy var textLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont(name: "Stolzl-Regular", size: 12)
        label.textAlignment = NSTextAlignment.left
        label.backgroundColor = .clear //.red
        label.textColor = .white
        label.text = ""
        label.numberOfLines = 0
        label.translatesAutoresizingMaskIntoConstraints = false
        label.lineBreakMode = NSLineBreakMode.byWordWrapping
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)

        setupLabel()

    }
    
    func setupLabel(){
        addSubview(textLabel)
        addConstraintsWithFormat("H:|-10-[v0]-10-|", views: textLabel)
        addConstraintsWithFormat("V:|-10-[v0]-10-|", views: textLabel)
    }

    override func prepareForReuse() {
        super.prepareForReuse()

    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Swift UIColictionView UICleageViewCell UIChationViewCompositionalLayout

评论


答:

1赞 deniz 11/8/2023 #1

我们显然不知道苹果是如何决定实现布局机制的。如果我们能看到他们的代码,我们大概可以准确地指出这里发生了什么。但是我过去在自己的应用程序中也遇到过类似的 UI 布局问题。我认为问题出在以下代码行之间的相互作用中:.estimated(n)

let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(40),  heightDimension: .absolute(40)).
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping

你基本上是对你的细胞的约束不足。a) 您的标签上允许无限行数。b) 你也允许用文字打破这些线条。c) 此外,您告诉布局引擎您不知道单元格(或标签)的大小 - 因为这是单元格中唯一的东西。重新加载视图后,截断的标签也满足了您对它们施加的约束,尽管这可能不是您的本意。

当约束不明确时,有多种方法可以满足约束。看起来,在第一次布局传递期间,布局引擎会选择一种方式来满足这些约束,而当您重新加载集合视图时,布局引擎会选择另一种方式。理想情况下,布局引擎是一致的,并且始终使用相同的方法来执行布局。这可能就是问题所在。我认为,如果您将 numberOfLines 属性切换为 1,将 NSLineBreakMode 切换为 byTruncatingTail,我的猜测是您将拥有更一致的布局体验。

我还建议调整您的估计大小,因为它应该接近您细胞的平均大小。从 gif 的表格视图中查看您的可能值 - 我可以说 40 点太小了。也许 120 点是一个更现实的估计。

评论

0赞 caa5042 11/8/2023
哇,真是个ios迅捷的国王。感谢您对为什么它的行为如此的详细解释..感谢您在我对您的其他线程发表评论后如此迅速地回复。我做了你建议的更改......它现在运行良好。