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

如何实现水平UICollectionView动态宽度单元格等间距布局

问题根源

你直接照搬了垂直滚动UICollectionView的等间距布局逻辑,和水平滚动场景的轴向逻辑完全不匹配:

  • 垂直滚动等间距布局的核心是调整x坐标,超出视图宽度时自动增加y值换行;但水平滚动场景下内容沿x轴延伸,你原代码的换行判断逻辑完全失效,还保留了系统FlowLayout默认给每个cell生成的换行y偏移,才会出现每放一个cell就占一行的问题
  • 你只实现了layoutAttributesForElements(in:),没有重写单个item的布局属性获取方法、没有处理布局刷新、没有计算正确的内容滚动范围,才会出现部分cell不显示的问题

正确实现代码

如果你的需求是水平滚动、动态宽度cell、cell间固定间距、所有cell在同一行垂直居中,可以直接用下面的实现:

class TagsLayout: UICollectionViewFlowLayout {
    
    let cellSpacing: CGFloat = 20
    
    override init(){
        super.init()
        scrollDirection = .horizontal
        // 开启动态宽度计算
        estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        minimumLineSpacing = 0
        minimumInteritemSpacing = 0
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        scrollDirection = .horizontal
        estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        minimumLineSpacing = 0
        minimumInteritemSpacing = 0
    }
    
    override func prepare() {
        super.prepare()
        // 计算垂直边距让所有cell居中显示
        guard let collectionView = collectionView else { return }
        let verticalInset = (collectionView.bounds.height - estimatedItemSize.height) / 2
        sectionInset = UIEdgeInsets(top: verticalInset, left: 16, bottom: verticalInset, right: 16)
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let attributes = super.layoutAttributesForElements(in: rect),
              let attributesToReturn = attributes.map({ $0.copy() }) as? [UICollectionViewLayoutAttributes],
              let collectionView = collectionView else {
            return nil
        }
        
        var currentX = sectionInset.left
        let centerY = collectionView.bounds.midY
        
        // 按item序号排序,从左到右依次排列
        for attr in attributesToReturn.sorted(by: { $0.indexPath.item < $1.indexPath.item }) {
            // 重置y坐标,所有cell垂直居中,彻底解决意外换行问题
            attr.center.y = centerY
            attr.frame.origin.x = currentX
            // 累加x偏移
            currentX = attr.frame.maxX + cellSpacing
        }
        
        return attributesToReturn
    }
    
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let attr = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes,
              let targetAttr = layoutAttributesForElements(in: attr.frame)?.first(where: { $0.indexPath == indexPath }) else {
            return super.layoutAttributesForItem(at: indexPath)
        }
        return targetAttr
    }
    
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        // 边界变化时自动刷新布局,避免旋转、尺寸变更时布局错乱
        return true
    }
    
    override var collectionViewContentSize: CGSize {
        guard let collectionView = collectionView,
              let itemCount = collectionView.dataSource?.collectionView(collectionView, numberOfItemsInSection: 0),
              itemCount > 0 else {
            return .zero
        }
        // 计算总内容宽度,保证最后一个cell可以完整滚动到可见区域
        var totalWidth = sectionInset.left + sectionInset.right
        for i in 0..<itemCount {
            let indexPath = IndexPath(item: i, section: 0)
            if let attr = layoutAttributesForItem(at: indexPath) {
                totalWidth += attr.frame.width
                if i != itemCount - 1 {
                    totalWidth += cellSpacing
                }
            }
        }
        return CGSize(width: totalWidth, height: collectionView.bounds.height)
    }
}

关键修改点

  • 删除了原代码中适配垂直滚动的换行判断逻辑,水平单行场景下直接按item序号从左到右排列即可
  • 统一设置所有cell的y轴中心点为collectionView垂直中点,消除系统默认生成的换行y偏移
  • 重写layoutAttributesForItem(at:),保证滚动过程中系统单独请求单个cell布局时返回正确属性,解决部分cell不显示的问题
  • 重写shouldInvalidateLayout(forBoundsChange:),保证视图尺寸变化、滚动时布局自动刷新
  • 重写collectionViewContentSize计算准确的内容宽度,避免最后一个cell被截断、无法滚动到可见区域的问题

异常效果参考

布局异常效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:36:27