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

如何实现UICollectionView竖屏2个横屏5个的自适应布局?

解决UICollectionView横竖屏适配布局问题

核心问题修正

  • 禁止重复创建CollectionView:原代码在旋转时会重建collectionView,既浪费资源又会丢失视图状态,只需在初始化时创建一次,旋转时仅更新布局参数。
  • 用容器可用宽度替代屏幕尺寸:屏幕尺寸包含系统状态栏、导航栏等占用空间,正确的可用宽度应为collectionView父视图的bounds.width减去左右安全区内边距。
  • 通过代理动态计算ItemSize:相比手动设置itemSize,实现UICollectionViewDelegateFlowLayout的sizeForItemAt方法,能精准适配容器尺寸变化与安全区。

具体代码修改

1. 初始化CollectionView(仅执行一次)

在viewDidLoad中完成collectionView的初始化,设置自动适配父视图尺寸:

override func viewDidLoad() {
    super.viewDidLoad()
    setupCollectionView()
}

private func setupCollectionView() {
    let layout = UICollectionViewFlowLayout()
    layout.minimumInteritemSpacing = 0
    layout.minimumLineSpacing = 0
    layout.scrollDirection = .vertical
    
    collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
    collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    collectionView.dataSource = self
    collectionView.delegate = self
    collectionView.register(CharacterCell.self, forCellWithReuseIdentifier: CharacterCell.reuseIdentifier)
    view.addSubview(collectionView)
}

2. 实现代理方法计算ItemSize

通过代理方法动态计算单元格尺寸,自动处理安全区:

extension YourViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        // 计算可用宽度:减去左右安全区内边距
        let availableWidth = collectionView.bounds.width - collectionView.safeAreaInsets.left - collectionView.safeAreaInsets.right
        
        let itemsPerRow: CGFloat = UIDevice.current.orientation.isPortrait ? 2 : 5
        let itemWidth = availableWidth / itemsPerRow
        // 保持正方形单元格
        return CGSize(width: itemWidth, height: itemWidth)
    }
}

3. 处理设备旋转刷新布局

在旋转时通知collectionView刷新布局,无需重建视图:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: { _ in
        self.collectionView.collectionViewLayout.invalidateLayout()
    })
}

额外优化:脱离设备方向依赖

若不想依赖UIDevice.current.orientation(避免设备方向与界面方向不一致的情况),可通过容器宽高比判断横竖屏:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let availableWidth = collectionView.bounds.width - collectionView.safeAreaInsets.left - collectionView.safeAreaInsets.right
    // 根据容器宽高比判断横竖屏
    let itemsPerRow: CGFloat = collectionView.bounds.width < collectionView.bounds.height ? 2 : 5
    let itemWidth = availableWidth / itemsPerRow
    return CGSize(width: itemWidth, height: itemWidth)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:30:41