代码之家  ›  专栏  ›  技术社区  ›  Mozahler

如何获得更均匀的单元格垂直距离?

  •  0
  • Mozahler  · 技术社区  · 7 年前

    我已经使用自动布局(没有故事板或XIB)动态创建了单元格,但布局管理器似乎是 将细胞配对,这样一个短的和一个高的细胞并排组成一行。

    screenshot

    我想要的是让单元格之间的距离均匀(垂直堆叠),而不是大的空白。因此,左边连续的三个短单元格在高度和位置上可能与右边的一个大单元格相等。换言之:所有单元格之间的垂直均匀距离。

      /// Everything is a side effect.  Configure the cell passed in
        ///
        /// - Parameters:
        ///   - cell: cell to format
        ///   - indexPath: index of cell
        func formatAutolayoutCell(cell: AutoResizingTextCell, at indexPath: IndexPath) {
            let event = eventsSource[indexPath.row]
            cell.layer.borderColor = event.calendar.cgColor
            cell.contentView.backgroundColor =  UIColor(cgColor: event.calendar.cgColor).withAlphaComponent(0.1)
    
            cell.titleLabel.text = event.title
    
            cell.contentView.addSubview(cell.titleLabel)
            cell.titleLabel.topAnchor.constraint(equalTo: cell.contentView.topAnchor).isActive = true
            cell.titleLabel.widthAnchor.constraint(equalToConstant: cellWidth).isActive = true
            cell.titleLabel.textColor = UIColor(cgColor: event.calendar.cgColor)
            cell.titleLabel.textAlignment = .center
    
            cell.contentView.addSubview(cell.bodyLabel)
            cell.bodyLabel.text = event.notes ?? ""
            cell.bodyLabel.widthAnchor.constraint(equalToConstant: cellWidth).isActive = true
            cell.bodyLabel.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor).isActive = true
            cell.titleLabel.bottomAnchor.constraint(equalTo: cell.bodyLabel.topAnchor).isActive = true
        }
    

    编辑:

    使用 Galo Torres Sevilla 我的建议是 UICollectionViewLayout . 它让我更接近我的目标,但是看起来单元格的数量是按列平均分配的,所以如果最左边的列有短的单元格,它会“早”用完单元格,并且左侧底部有很多空间。我可能需要按大小对单元格进行排序,以获得更好的分布。

    second version

    1 回复  |  直到 7 年前
        1
  •  1
  •   Galo Torres Sevilla    7 年前

    遵循代码 https://www.raywenderlich.com/392-uicollectionview-custom-layout-tutorial-pinterest

    您可以将uiCollectionViewFlowLayout子类化,以获得所需的内容。

    这是它的主要代码。 注:代码来自上述网站

    import UIKit
    
    protocol PinterestLayoutDelegate: class {
      // 1. Method to ask the delegate for the height of the image
      func collectionView(_ collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat
    }
    
    class PinterestLayout: UICollectionViewLayout {
      //1. Pinterest Layout Delegate
      weak var delegate: PinterestLayoutDelegate!
    
      //2. Configurable properties
      fileprivate var numberOfColumns = 2
      fileprivate var cellPadding: CGFloat = 6
    
      //3. Array to keep a cache of attributes.
      fileprivate var cache = [UICollectionViewLayoutAttributes]()
    
      //4. Content height and 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)
      }
    
      override var collectionViewContentSize: CGSize {
        return CGSize(width: contentWidth, height: contentHeight)
      }
    
      override func prepare() {
        // 1. Only calculate once
        guard cache.isEmpty == true, let collectionView = collectionView else {
          return
        }
        // 2. Pre-Calculates the X Offset for every column and adds an array to increment the currently max Y Offset for each column
        let columnWidth = contentWidth / CGFloat(numberOfColumns)
        var xOffset = [CGFloat]()
        for column in 0 ..< numberOfColumns {
          xOffset.append(CGFloat(column) * columnWidth)
        }
        var column = 0
        var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)
    
        // 3. Iterates through the list of items in the first section
        for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
    
          let indexPath = IndexPath(item: item, section: 0)
    
          // 4. Asks the delegate for the height of the picture and the annotation and calculates the cell frame.
          let photoHeight = delegate.collectionView(collectionView, heightForPhotoAtIndexPath: indexPath)
          let height = cellPadding * 2 + photoHeight
          let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
          let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
    
          // 5. Creates an UICollectionViewLayoutItem with the frame and add it to the cache
          let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
          attributes.frame = insetFrame
          cache.append(attributes)
    
          // 6. Updates the collection view content height
          contentHeight = max(contentHeight, frame.maxY)
          yOffset[column] = yOffset[column] + height
    
          column = column < (numberOfColumns - 1) ? (column + 1) : 0
        }
      }
    
      override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    
        var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
    
        // Loop through the cache and look for items in the rect
        for attributes in cache {
          if attributes.frame.intersects(rect) {
            visibleLayoutAttributes.append(attributes)
          }
        }
        return visibleLayoutAttributes
      }
    
      override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return cache[indexPath.item]
      }
    
    }