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

iOS Swift如何用同一UICollectionView切换列表、网格、瀑布流布局

实现方案

完全可以用同一个UICollectionView实现三种布局切换,具体实现步骤如下:


1. 新增布局状态管理

在控制器的Properties代码块中新增布局类型枚举和当前布局状态变量:

// 定义三种布局类型
enum LayoutType {
    case list // 单行列表布局
    case grid // 双列网格布局(原有默认布局)
    case staggered // 瀑布流布局
}
// 当前布局状态,默认是双列网格
var currentLayout: LayoutType = .grid

2. 实现三种布局的构造方法

推荐用iOS13+支持的UICollectionViewCompositionalLayout实现列表、网格布局,瀑布流用通用自定义布局实现,新增布局构造方法:

func getCurrentLayout() -> UICollectionViewLayout {
    switch currentLayout {
    case .list:
        // 单行列表布局:宽度撑满父视图,高度可自定义或自适应
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(260))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(260))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = lineSpacing
        section.contentInsets = .init(top: 10, leading: 10, bottom: 10, trailing: 10)
        return UICollectionViewCompositionalLayout(section: section)
        
    case .grid:
        // 原有双列网格布局:正方形item
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = .init(top: 0, leading: interitemSpacing/2, bottom: 0, trailing: interitemSpacing/2)
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.5))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = lineSpacing
        section.contentInsets = .init(top: 10, leading: 10, bottom: 10, trailing: 10)
        return UICollectionViewCompositionalLayout(section: section)
        
    case .staggered:
        // 瀑布流布局:用通用自定义StaggeredGridLayout实现
        let layout = StaggeredGridLayout()
        layout.numberOfColumns = 2
        layout.cellPadding = interitemSpacing
        layout.delegate = self
        return layout
    }
}

3. 实现瀑布流高度计算代理

瀑布流需要根据图片比例动态计算每个cell的高度,先声明瀑布流布局代理,再让控制器遵守协议:

// 瀑布流布局代理协议
protocol StaggeredGridLayoutDelegate: AnyObject {
    func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat
}

// 控制器实现代理方法
extension HotViewController: StaggeredGridLayoutDelegate {
    func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat {
        let photo = filterSwitch.isOn ? filteredPhotos[indexPath.row] : hotPhotos[indexPath.row]
        // 根据图片宽高比计算cell高度
        let cellWidth = (view.bounds.width - 20 - interitemSpacing) / 2
        let imageRatio = CGFloat(photo.height) / CGFloat(photo.width)
        return cellWidth * imageRatio + 20 // 20为cell内边距/其他控件预留高度
    }
}

4. 绑定按钮点击事件实现布局切换

给两个按钮绑定点击方法,切换布局时支持动画过渡:

// 按钮1点击:切换为单行列表布局
@IBAction func listBtnClicked(_ sender: UIButton) {
    currentLayout = .list
    collectionView.setCollectionViewLayout(getCurrentLayout(), animated: true)
    collectionView.reloadData()
}

// 按钮2点击:切换为瀑布流布局
@IBAction func staggeredBtnClicked(_ sender: UIButton) {
    currentLayout = .staggered
    collectionView.setCollectionViewLayout(getCurrentLayout(), animated: true)
    collectionView.reloadData()
}

// 如需切回双列网格,补充对应点击方法即可
@IBAction func gridBtnClicked(_ sender: UIButton) {
    currentLayout = .grid
    collectionView.setCollectionViewLayout(getCurrentLayout(), animated: true)
    collectionView.reloadData()
}

5. 调整原有代码

  • 删除原有UICollectionViewDelegateFlowLayout相关的所有代理方法,改为用上述布局方法控制尺寸
  • 在viewDidLoad中初始化默认布局:
override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.collectionViewLayout = getCurrentLayout()
    setupViewModel()
}

注意事项

  • PhotoListCell需要做好自动布局适配,确保内部图片控件可以跟随cell尺寸自动缩放
  • 如果需要兼容iOS13以下版本,将列表、网格布局也改为自定义FlowLayout实现即可,逻辑完全一致
  • 自定义StaggeredGridLayout是通用成熟实现,可直接使用通用开源代码,无需从零开发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 02:45:03