如何修改横向UICollectionView的数据源展示排列方式?
UICollectionView横向滚动布局调整实现思路
核心参数确认
先明确几个固定布局参数(根据你的示例):
- 每页列数:
columnsPerPage = 4 - 每页行数:
rowsPerPage = 2 - 每页总Item数:
itemsPerPage = columnsPerPage * rowsPerPage = 8
方法一:调整数据源映射(无需修改布局)
在collectionView(_:cellForItemAt:)方法中,将原IndexPath的Item索引转换为目标排列对应的数据源索引,直接取对应数据渲染即可。
转换逻辑:
- 计算当前Item所在的页码:
pageIndex = indexPath.item / itemsPerPage - 计算当前Item在页内的位置:
posInPage = indexPath.item % itemsPerPage - 拆分原布局的列和行:
col = posInPage / rowsPerPage,row = posInPage % rowsPerPage - 计算目标布局的页内位置:
targetPosInPage = row * columnsPerPage + col - 最终数据源索引:
targetItemIndex = pageIndex * itemsPerPage + targetPosInPage
代码示例:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID", for: indexPath) as! CustomCell let itemsPerPage = 4 * 2 // 4列×2行 let pageIndex = indexPath.item / itemsPerPage let posInPage = indexPath.item % itemsPerPage let col = posInPage / 2 let row = posInPage % 2 let targetItemIndex = pageIndex * itemsPerPage + row * 4 + col // 用targetItemIndex取数据源数据 cell.data = dataSource[targetItemIndex] return cell }
方法二:自定义UICollectionViewLayout(无需修改数据源)
直接重写布局逻辑,让Cell按目标排列方式计算frame,数据源保持原顺序即可。
核心步骤:
- 在
prepare()中提前计算所有Cell的布局属性; - 在
layoutAttributesForItemAt(_:)中,根据IndexPath计算Cell的位置:- 计算页码和页内位置;
- 按目标排列(先每行4个,再下一行)拆分行列;
- 计算Cell的x、y坐标(横向滚动时,页码决定x的偏移量)。
代码示例:
class CustomFlowLayout: UICollectionViewFlowLayout { private let columnsPerPage = 4 private let rowsPerPage = 2 private var layoutAttributes = [UICollectionViewLayoutAttributes]() override func prepare() { super.prepare() guard let collectionView = collectionView else { return } layoutAttributes.removeAll() let itemsPerPage = columnsPerPage * rowsPerPage let totalItems = collectionView.numberOfItems(inSection: 0) let cellWidth = collectionView.bounds.width / CGFloat(columnsPerPage) let cellHeight = collectionView.bounds.height / CGFloat(rowsPerPage) for itemIndex in 0..<totalItems { let indexPath = IndexPath(item: itemIndex, section: 0) let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) let pageIndex = itemIndex / itemsPerPage let posInPage = itemIndex % itemsPerPage // 目标排列:先按行分配 let row = posInPage / columnsPerPage let col = posInPage % columnsPerPage let x = CGFloat(pageIndex) * collectionView.bounds.width + CGFloat(col) * cellWidth let y = CGFloat(row) * cellHeight attributes.frame = CGRect(x: x, y: y, width: cellWidth, height: cellHeight) layoutAttributes.append(attributes) } } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { return layoutAttributes[indexPath.item] } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { return layoutAttributes.filter { $0.frame.intersects(rect) } } override var collectionViewContentSize: CGSize { guard let collectionView = collectionView else { return .zero } let totalItems = collectionView.numberOfItems(inSection: 0) let itemsPerPage = columnsPerPage * rowsPerPage let totalPages = (totalItems + itemsPerPage - 1) / itemsPerPage return CGSize(width: CGFloat(totalPages) * collectionView.bounds.width, height: collectionView.bounds.height) } }
内容的提问来源于stack exchange,提问作者Beginnerrrrrr
相关产品推荐
相关产品推荐

