Элементы в UICollectionView с пользовательским UICollectionViewFlowLayout показывают элементы друг под другом, а не в сетке - PullRequest
1 голос
/ 24 апреля 2020

В настоящее время я работаю над приложением, в котором нам нужно показывать элементы в сетке с фиксированным числом столбцов. Так что UICollectionView с пользовательским UICollectionViewFlowLayout отлично подходит для этого!

Я создал следующий пользовательский UICollectionViewFlowLayout, который вычисляет размер элемента в зависимости от ширины collectionView / контейнера, желаемого количества столбцов и желаемого расстояния между элементами (слева от первого элемента, между элементами, и право последнего пункта). Поэтому, если нам нужны два столбца, это будет выглядеть так:

интервал - элемент - интервал - элемент - интервал

Пользовательский UICollectionViewFlowLayout

import UIKit

class MultiColumnCollectionViewFlowLayout: UICollectionViewFlowLayout {

  let columnCount: Int = 2
  let itemAspectRatio: CGFloat = 0.71
  let spacing: CGFloat = 8

  var containerWidth: CGFloat = .zero {
    didSet {
      if containerWidth != oldValue {
        self.invalidateLayout()
      }
    }
  }

  // MARK: - Init

  override init() {
    super.init()
    self.configure()
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    self.configure()
  }

  // MARK: - Layout

  override func invalidateLayout() {
    super.invalidateLayout()
    self.configure()
  }

  func configure() {
    self.scrollDirection = .vertical
    self.itemSize = UICollectionViewFlowLayout.automaticSize
    self.sectionInset = UIEdgeInsets(top: spacing, left: spacing, bottom: spacing, right: spacing)
    self.minimumLineSpacing = spacing

    let numberOfSpacings = CGFloat(columnCount + 1)
    let itemWidth: CGFloat = (containerWidth-(spacing*numberOfSpacings))/CGFloat(columnCount)
    self.estimatedItemSize = CGSize(width: itemWidth, height: itemWidth*itemAspectRatio)
  }

  override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    guard let att = super.layoutAttributesForElements(in: rect) else { return [UICollectionViewLayoutAttributes]() }
    var x: CGFloat = sectionInset.left
    var y: CGFloat = -1.0

    for a in att {
        if a.representedElementCategory != .cell { continue }

        if a.frame.origin.y >= y { x = sectionInset.left }
        a.frame.origin.x = x
        x += a.frame.width + minimumInteritemSpacing
        y = a.frame.maxY
    }
    return att
  }
}

Проблема:

С 1 элементом он работает, как и ожидалось: enter image description here

С несколькими элементами (скажем, 3 элемента), это показывает это (не ожидается): enter image description here

То, что я хочу, происходит примерно так: enter image description here

Забавный факт: когда я пытаюсь это сделать на iPad с 3 столбцами, разным интервалом и разным соотношением сторон элемента, он отлично работает: enter image description here

Я отладил его и для сценария с 2 столбцами на iPhone 8 (iOS 13.3) (снимки сделаны на этом устройстве), itemAspectRatio 0.71 и интервал 8 (поэтому ширина представления сбора составляет 375 при iPhone 8), itemWidth должен быть 175,5. Это именно та ширина элемента, когда я отлаживаю его, если вы вычисляете 175,5 + 175,5 + 8 + 8 + 8 = 375 (2 элемента + 3 раза интервал), так что это должно идеально соответствовать. По какой-то причине это не так. Допустим, это сводит меня с ума. Пожалуйста, помогите.

...