iOS瀑布流的简单实现(Swift)

2020-01-18 18:13:34于丽

<2>下面介绍第二种(Swift实现)

效果图如下所示:
ios瀑布流的实现,ios瀑布流实现原理,ios瀑布流的实现原理

这种实现方法就是比较成熟的了,我把它封装成一个类.其实主要是实现三个函数

1)重写父类的prepare方法,准备所有cell的样式


 extension WaterfallLayout {
  // prepare准备所有Cell的布局样式
  override func prepare() {
    super.prepare()
    
    // 0.获取item的个数
    let itemCount = collectionView!.numberOfItems(inSection: 0)
    
    // 1.获取列数
    let cols = dataSource?.numberOfColsInWaterfallLayout?(self) ?? 2
    
    // 2.计算Item的宽度
    let itemW = (collectionView!.bounds.width - self.sectionInset.left - self.sectionInset.right - self.minimumInteritemSpacing * CGFloat((cols - 1))) / CGFloat(cols)
    
    // 3.计算所有的item的属性
    for i in startIndex..<itemCount {
      // 1.设置每一个Item位置相关的属性
      let indexPath = IndexPath(item: i, section: 0)
      
      // 2.根据位置创建Attributes属性
      let attrs = UICollectionViewLayoutAttributes(forCellWith: indexPath)
      
      // 3.随机一个高度
      guard let height = dataSource?.waterfallLayout(self, indexPath: indexPath) else {
        fatalError("请设置数据源,并且实现对应的数据源方法")
      }
      
      // 4.取出最小列的位置
      var minH = colHeights.min()!
      let index = colHeights.index(of: minH)!
      minH = minH + height + minimumLineSpacing
      colHeights[index] = minH
      
      // 5.设置item的属性
      attrs.frame = CGRect(x: self.sectionInset.left + (self.minimumInteritemSpacing + itemW) * CGFloat(index), y: minH - height - self.minimumLineSpacing, width: itemW, height: height)
      attrsArray.append(attrs)
    }
    
    // 4.记录最大值
    maxH = colHeights.max()!
    
    // 5.给startIndex重新复制
    startIndex = itemCount
  }
}

2)返回设置cell样式的数组


 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return attrsArray
  }

3)返回当前的contentSize


override var collectionViewContentSize: CGSize {
    return CGSize(width: 0, height: maxH + sectionInset.bottom - minimumLineSpacing)
  }

总结:

在下面我封装的这个类中,只需要遵守我的数据代理源协议并且实现我的协议中的两个方法,传给我对应得高度(我这里是传的随机的),可选的方法,若是不实现,会有一个默认值,就可以实现该功能.协议如下:


@objc protocol WaterfallLayoutDataSource : class {
  func waterfallLayout(_ layout : WaterfallLayout, indexPath : IndexPath) -> CGFloat
  @objc optional func numberOfColsInWaterfallLayout(_ layout : WaterfallLayout) -> Int
}