如何使用Swift 4实现如图所示的UICollectionView多图布局?
搞定UICollectionView多图布局的实用方案
嘿,我看你现在用UICollectionViewDelegateFlowLayout做两行三列布局没达到预期,问题大概率出在你只处理了前两个item的尺寸,没覆盖所有情况,而且可能没统一配置间距,导致布局错乱。我给你整理了一套可行的方案,你可以根据自己要的效果调整:
先统一配置间距,别硬编码
首先定义几个常量,方便后续调整,避免到处写死数值:
private let itemGap: CGFloat = 2 // item之间的横向间距 private let lineGap: CGFloat = 2 // 行与行之间的纵向间距 private let sectionPadding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // 整个section的内边距
完整实现sizeForItemAt方法
我猜你想要的要么是「第一行两个大item,第二行三个小item」的布局,要么是首item占整行、后面三列的布局,我都给你写出来:
情况1:第一行2个等宽item,第二行3个等宽item(标准两行三列)
这应该是你最初的目标,直接用这段代码:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // 先算出整个collectionView的可用宽度 let totalAvailableWidth = UIScreen.main.bounds.width - sectionPadding.left - sectionPadding.right if indexPath.item < 2 { // 前两个item在第一行,要减去1个横向间距 let itemWidth = (totalAvailableWidth - itemGap) / 2 return CGSize(width: itemWidth, height: itemWidth * 0.8) // 高度可以自己调比例,比如0.8是宽高比5:4 } else { // 后面的item在第二行,三个要减去2个横向间距 let itemWidth = (totalAvailableWidth - 2 * itemGap) / 3 return CGSize(width: itemWidth, height: itemWidth) // 正方形的话直接用宽度当高度 } }
情况2:首item占整行,第二行3个等宽item(常见的多图封面布局)
如果是这种不规则布局,就用下面的代码:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let totalAvailableWidth = UIScreen.main.bounds.width - sectionPadding.left - sectionPadding.right switch indexPath.item { case 0: // 第一个item占整行,高度按4:3比例设置,你也可以改成固定高度 return CGSize(width: totalAvailableWidth, height: totalAvailableWidth * 0.75) case 1,2,3: // 第二行三个正方形item let itemWidth = (totalAvailableWidth - 2 * itemGap) / 3 return CGSize(width: itemWidth, height: itemWidth) default: // 如果还有更多item,就按第二行的尺寸返回 let itemWidth = (totalAvailableWidth - 2 * itemGap) / 3 return CGSize(width: itemWidth, height: itemWidth) } }
别忘了补充这几个代理方法
光设置尺寸还不够,得把间距也配置好,不然布局会挤在一起或者有空白:
// 设置item之间的最小横向间距 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return itemGap } // 设置行与行之间的最小纵向间距 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return lineGap } // 设置section的内边距 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return sectionPadding }
最后排查几个常见坑
- 检查你的UICollectionView约束是不是正确,确保它的宽度是你想要的(比如屏幕宽,或者父容器宽)
- 确认数据源返回的item数量够填两行(比如情况1需要至少5个item,情况2需要至少4个)
- 如果高度不对,直接调整
sizeForItemAt里的height值就行,比如改成固定的150之类的
内容的提问来源于stack exchange,提问作者Gorib Developer
相关产品推荐
相关产品推荐

