如何在单Section的CollectionView中设置单元格差异化间距?
针对你要在单Section的CollectionView里让中间单元格和两侧间距更大、其他保持不变的需求,用UICollectionViewFlowLayout的代理方法就能轻松搞定,不需要自定义布局,下面给你具体的实现思路:
方法一:利用UICollectionViewDelegateFlowLayout的item内边距代理方法(iOS 11+)
这是最直接的方案,通过给特定单元格设置额外的内边距,来拉大它和相邻单元格的间距:
先设置基础的全局最小间距
实现collectionView(_:layout:minimumInteritemSpacingForSectionAt:)方法,返回你想要的常规单元格间距(比如8pt):func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return 8 // 常规单元格间的基础间距 }给中间单元格设置差异化内边距
实现collectionView(_:layout:insetForItemAt:)方法,判断当前单元格是否是你要突出的中间单元格,给它添加左右(横向布局)或上下(纵向布局)的额外内边距:func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForItemAt indexPath: IndexPath) -> UIEdgeInsets { // 假设总共有5个单元格,中间的是索引为2的那个(从0开始) let totalItems = collectionView.numberOfItems(inSection: indexPath.section) let middleIndex = totalItems / 2 if indexPath.item == middleIndex { // 给中间单元格左右各加16pt内边距,这样和两侧的间距会变成8+16=24pt return UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) } else { // 其他单元格用默认内边距 return UIEdgeInsets.zero } }保证白色圆圈不碰边缘
只要你的白色圆圈是单元格contentView的子视图,并且给圆圈设置了和contentView边缘的约束(比如上下左右各留2pt的空白),或者直接让圆圈的尺寸比contentView小一点,就不会碰到相邻单元格的边缘了。如果你的单元格尺寸就是圆圈的尺寸,那通过上面的内边距拉大的间距也足够隔开圆圈。
方法二:动态调整单元格尺寸(兼容iOS 11以下)
如果需要支持iOS 11之前的系统,没有insetForItemAt方法,那可以通过调整中间单元格的尺寸来实现间距差异:
设置基础最小间距
同样先设置minimumInteritemSpacingForSectionAt为常规间距(比如8pt)。调整中间单元格的尺寸
实现collectionView(_:layout:sizeForItemAt:)方法,给中间单元格的宽度(横向布局)或高度(纵向布局)增加额外的数值,同时根据整体布局需求调整其他单元格的尺寸,保证布局连贯:func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let totalItems = collectionView.numberOfItems(inSection: indexPath.section) let middleIndex = totalItems / 2 let normalSize = CGSize(width: 60, height: 60) // 常规单元格的尺寸 let extraSpacing = 32 // 中间单元格需要额外增加的宽度(对应左右各16pt的间距) if indexPath.item == middleIndex { return CGSize(width: normalSize.width + extraSpacing, height: normalSize.height) } else { // 若横向布局且单元格数量较多,可适当缩小常规单元格尺寸,避免整体超出可滚动范围 return normalSize } }
额外提示:动态中间单元格(比如选中的单元格)
如果你的“中间单元格”不是固定位置,而是当前选中的单元格,只需要把上面判断indexPath.item == middleIndex的逻辑改成判断indexPath.item == selectedIndex(selectedIndex是你维护的选中索引变量),然后在选中状态变化时调用collectionView.reloadItems(at: [indexPath])刷新布局即可。
内容的提问来源于stack exchange,提问作者Frilau

