UICollectionView自定义布局中间列开始更高

时间:2017-11-21 17:41:07

标签: ios swift uicollectionview

我现在正在垂直滚动UICollectionView。我希望看起来像这样=,其中中间行开始比其他两行高一点,以创建一个很酷而有趣的效果。 关于如何实现这一点的任何想法?

enter image description here

1 个答案:

答案 0 :(得分:2)

可以通过创建custom layout class来实现集合视图布局。

<强>理论值:

基本上,集合视图直接与自定义布局对象一起工作,以管理整个布局过程,询问所需的布局信息。

在布局过程中,集合视图调用布局对象的特定方法。这些方法提供了计算项目位置和为集合视图提供所需主要信息的机会。

在布局过程中,始终按顺序调用以下方法:

  1. prepare():执行提供布局信息所需的前期计算
  2. collectionViewContentSize:根据初始计算返回整个内容区域的整体大小
  3. layoutAttributesForElements(in:):返回指定矩形中的单元格和视图的属性
  4. <强>实践:

    1. 先决条件:假设我们有一个Collection视图并配置了 数据源和代理人,让我们创建一个UICollectionViewLayout 子类。我把它命名为HiveLayout。我也把它分配给了 故事板中的collectionView。我们还需要一些在过程中有用的变量

      //    Properties for configuring the layout: the number of columns and the cell padding.
      fileprivate var numberOfColumns = 3
      fileprivate var cellPadding: CGFloat = 10
      
      //    Cache the calculated attributes. When you call prepare(), you’ll calculate the attributes for all items and add them to the cache. You can be efficient and query the cache instead of recalculating them every time.
      fileprivate var cache = [UICollectionViewLayoutAttributes]()
      
      //    Properties to store the content size.
      fileprivate var contentHeight: CGFloat = 0
      fileprivate var contentWidth: CGFloat {
          guard let collectionView = collectionView else {
              return 0
          }
          let insets = collectionView.contentInset
          return collectionView.bounds.width - (insets.left + insets.right)
      }
      
    2. prepare():这是我们实际计算单元格属性的地方

      override func prepare() {
          // If cache is empty and the collection view exists – calculate the layout attributes
          guard cache.isEmpty == true, let collectionView = collectionView else {
              return
          }
      
          // xOffset: array with the x-coordinate for every column based on the column widths
          // yOffset: array with the y-position for every column, Using odd-even logic to push the even cell upwards and odd cells down.
          let columnWidth = contentWidth / CGFloat(numberOfColumns)
          var xOffset = [CGFloat]()
          for column in 0 ..< numberOfColumns {
              xOffset.append(CGFloat(column) * columnWidth)
          }
          var column = 0
      
          var yOffset = [CGFloat]()
          for i in 0..<numberOfColumns {
              yOffset.append((i % 2 == 0) ? (columnWidth / 2) : 0)
          }
      
          for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
      
              let indexPath = IndexPath(item: item, section: 0)
      
              // Calculate insetFrame that can be set to the attribute
              let cellHeight = columnWidth - (cellPadding * 2)
              let height = cellPadding * 2 + cellHeight
              let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
              let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
      
              // Create an instance of UICollectionViewLayoutAttribute, sets its frame using insetFrame and appends the attributes to cache.
              let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
              attributes.frame = insetFrame
              cache.append(attributes)
      
              // Update the contentHeight to account for the frame of the newly calculated item. It then advances the yOffset for the current column based on the frame
              contentHeight = max(contentHeight, frame.maxY)
              yOffset[column] = yOffset[column] + height
      
              column = column < (numberOfColumns - 1) ? (column + 1) : 0
          }
      }
      
    3. <强> collectionViewContentSize

      //    Using contentWidth and contentHeight, calculate collectionViewContentSize.
      override var collectionViewContentSize: CGSize {
          return CGSize(width: contentWidth, height: contentHeight)
      }
      
    4. layoutAttributesForElements(in:)

      override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
      
          var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
      
          for attributes in cache {
              if attributes.frame.intersects(rect) {
                  visibleLayoutAttributes.append(attributes)
              }
          }
          return visibleLayoutAttributes
      }
      
    5. layoutAttributesForItem(at:) :返回特定单元格的属性

      override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
          return cache[indexPath.item]
      }
      
    6. 请查看gist的布局类。

      这是在行动!!

      Demo