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

如何在UICollectionView Flow Layout中实现带中间通道的巴士座位表

如何用UICollectionViewFlowLayout实现巴士座位中间的通道间距

嘿,作为iOS新手刚接触UICollectionView布局,遇到这种需求完全不用慌!我给你两种实用方案,从简单易上手到灵活自定义,你可以根据自己的项目情况选择:

方案一:用多Section实现通道(最适合新手)

这种方法不用写复杂的自定义布局,只需要把座位分成左排和右排两个Section,然后通过Section的内边距来留出中间的通道:

步骤1:划分座位数据

把你的座位数据源拆成两个数组,一个存左排座位,一个存右排座位,对应UICollectionView的两个Section。

步骤2:实现FlowLayout代理方法

在你的ViewController里(或者专门的代理类)实现UICollectionViewDelegateFlowLayout的以下方法,给两个Section设置左右内边距,凑出中间的通道宽度:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let aisleHalfWidth: CGFloat = 20 // 通道总宽度是40,左右各留20
    let sidePadding: CGFloat = 16 // 左右两侧的边距
    
    if section == 0 { // 左排座位
        return UIEdgeInsets(top: 16, left: sidePadding, bottom: 16, right: aisleHalfWidth)
    } else { // 右排座位
        return UIEdgeInsets(top: 16, left: aisleHalfWidth, bottom: 16, right: sidePadding)
    }
}

// 别忘了设置每个座位的大小
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: 60, height: 60) // 根据你的需求调整
}

这样两个Section之间就会自动留出40的通道宽度,左排和右排的座位也会整齐排列,新手很容易上手!

方案二:自定义UICollectionViewFlowLayout(更灵活)

如果不想拆分Section,想在同一个Section里实现完整的座位布局(包括通道),可以自定义FlowLayout,通过重写布局方法来手动调整每个座位的位置:

步骤1:创建自定义FlowLayout类

新建一个继承自UICollectionViewFlowLayout的类,比如BusSeatLayout,然后重写两个关键方法:

class BusSeatLayout: UICollectionViewFlowLayout {
    // 自定义通道宽度,可根据需求调整
    var aisleWidth: CGFloat = 40
    // 每行的座位数(左右各2个,总共4个)
    private let itemsPerRow = 4
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let originalAttrs = super.layoutAttributesForElements(in: rect) else { return nil }
        // 复制原属性,避免修改系统默认数据
        let attrs = originalAttrs.map { $0.copy() as! UICollectionViewLayoutAttributes }
        
        // 计算每个座位的宽度(减去边距、座位间距和通道宽度后平分)
        let totalAvailableWidth = collectionView!.bounds.width 
            - sectionInset.left 
            - sectionInset.right 
            - minimumInteritemSpacing * CGFloat(itemsPerRow - 1) 
            - aisleWidth
        let itemWidth = totalAvailableWidth / CGFloat(itemsPerRow)
        
        for attr in attrs {
            let itemIndex = attr.indexPath.item
            let row = itemIndex / itemsPerRow // 当前座位所在的行
            let column = itemIndex % itemsPerRow // 当前座位所在的列
            
            // 计算基础X坐标
            var xPos = sectionInset.left + CGFloat(column) * (itemWidth + minimumInteritemSpacing)
            
            // 如果是右半部分的座位(第2、3列,从0开始计数),加上通道宽度
            if column >= 2 {
                xPos += aisleWidth
            }
            
            // 计算Y坐标
            let yPos = sectionInset.top + CGFloat(row) * (itemSize.height + minimumLineSpacing)
            
            // 更新座位的frame
            attr.frame = CGRect(x: xPos, y: yPos, width: itemWidth, height: itemSize.height)
        }
        
        return attrs
    }
    
    // 重写内容尺寸计算,确保滚动范围正确
    override var collectionViewContentSize: CGSize {
        guard let collectionView = collectionView else { return .zero }
        let totalItems = collectionView.numberOfItems(inSection: 0)
        let totalRows = CGFloat((totalItems + itemsPerRow - 1) / itemsPerRow) // 向上取整计算总行数
        let contentHeight = sectionInset.top 
            + sectionInset.bottom 
            + totalRows * (itemSize.height + minimumLineSpacing) 
            - minimumLineSpacing // 减去最后一行的底部间距
        
        return CGSize(width: collectionView.bounds.width, height: contentHeight)
    }
}

步骤2:给CollectionView设置自定义Layout

在你的ViewController里,初始化这个自定义Layout并设置给CollectionView:

override func viewDidLoad() {
    super.viewDidLoad()
    
    let seatLayout = BusSeatLayout()
    seatLayout.itemSize = CGSize(width: 60, height: 60)
    seatLayout.minimumInteritemSpacing = 8 // 座位之间的横向间距
    seatLayout.minimumLineSpacing = 12 // 行与行之间的纵向间距
    seatLayout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
    seatLayout.aisleWidth = 40 // 设置通道宽度
    
    collectionView.collectionViewLayout = seatLayout
    // 其他CollectionView设置(注册Cell、设置数据源等)
}

小贴士

  • 如果你的巴士座位是左右各3列,只需要把itemsPerRow改成6,然后判断column >=3时加上通道宽度就行
  • 测试时可以给每个Cell设置不同的背景色,方便观察布局是否正确
  • 如果需要区分靠窗、过道座位,还可以在layoutAttributesForElements里给不同列的座位设置不同的尺寸或样式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:25:22