You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift iOS实现水平滚动三行动态宽度等间距UICollectionView布局

3行水平滚动自适应宽度UICollectionView左对齐布局修复方案

问题现象

需要实现3行、水平滚动、单元格宽度自适应、单元格等间距、布局左对齐的类安卓水平列表效果,当前实现存在单元格无法左对齐的布局异常:
当前异常效果示意图

原有问题代码

集合视图初始化代码

func setUpCollectionView() {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = UICollectionView.ScrollDirection.horizontal
    layout.minimumInteritemSpacing = 16
    layout.minimumLineSpacing = 12

    layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    collectionView.semanticContentAttribute = UISemanticContentAttribute.forceLeftToRight
    collectionView.contentInsetAdjustmentBehavior = .always
    collectionView.collectionViewLayout = layout
}

代理实现代码

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    let extraSpace : CGFloat = 50.0

    return CGSize(width: (self.viewModels?.car_problems?[indexPath.item].problem?.size(withAttributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 17)]).width ?? 34) + extraSpace, height: 32)

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 16
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return 12
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsets(top: 5, left: 16, bottom: 0, right: 16)
}

预期效果

预期效果示意图

问题原因

  1. 原生UICollectionViewFlowLayout在水平滚动模式下,默认会自动填充每行剩余空间,将单元格做居中/两端分散对齐,没有内置左对齐逻辑
  2. 同时设置estimatedItemSize = UICollectionViewFlowLayout.automaticSize和实现sizeForItemAt返回准确尺寸,两套尺寸计算逻辑冲突,会加剧布局错位
  3. 原有代码中布局初始化和代理方法返回的间距参数数值不一致,也会导致布局计算异常

修复步骤

  • 第一步:删除layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize配置,已经通过sizeForItemAt返回准确单元格尺寸,不需要自动估算
  • 第二步:自定义左对齐FlowLayout子类,重写布局属性计算逻辑,强制所有单元格左对齐,保持设定的等间距
  • 第三步:用自定义布局替换原有的原生FlowLayout初始化,统一配置间距、内边距参数,删除重复的间距代理方法避免数值冲突

自定义左对齐布局代码

class LeftAlignedHorizontalFlowLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil }
        // 按y轴坐标分组,同一midY的元素属于同一行
        var rowGroups = [CGFloat: [UICollectionViewLayoutAttributes]]()
        for attr in attributes {
            let rowKey = attr.frame.midY
            if rowGroups[rowKey] == nil {
                rowGroups[rowKey] = []
            }
            rowGroups[rowKey]?.append(attr)
        }
        // 每行从左到右按固定间距重新排列
        for (_, rowAttrs) in rowGroups {
            var currentX: CGFloat = sectionInset.left
            for attr in rowAttrs.sorted(by: { $0.frame.minX < $1.frame.minX }) {
                var frame = attr.frame
                frame.origin.x = currentX
                attr.frame = frame
                currentX = frame.maxX + minimumInteritemSpacing
            }
        }
        return attributes
    }
}

修改后的集合视图初始化代码

func setUpCollectionView() {
    let layout = LeftAlignedHorizontalFlowLayout()
    layout.scrollDirection = .horizontal
    // 垂直方向相邻行的间距
    layout.minimumLineSpacing = 12
    // 同一行内水平方向相邻单元格的间距
    layout.minimumInteritemSpacing = 16
    // 统一配置section内边距,和原有需求一致
    layout.sectionInset = UIEdgeInsets(top: 5, left: 16, bottom: 0, right: 16)
    
    collectionView.semanticContentAttribute = .forceLeftToRight
    collectionView.contentInsetAdjustmentBehavior = .always
    collectionView.collectionViewLayout = layout
}

注意:如果需要支持多section场景,只需要在自定义布局里补充section的x轴偏移计算逻辑即可,当前代码适配单section场景完全符合需求。

内容的提问来源于stack exchange,提问作者Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:48:24