В настоящее время я работаю над приложением, в котором нам нужно показывать элементы в сетке с фиксированным числом столбцов. Так что 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 элементом он работает, как и ожидалось:
С несколькими элементами (скажем, 3 элемента), это показывает это (не ожидается):
То, что я хочу, происходит примерно так:
Забавный факт: когда я пытаюсь это сделать на iPad с 3 столбцами, разным интервалом и разным соотношением сторон элемента, он отлично работает:
Я отладил его и для сценария с 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 раза интервал), так что это должно идеально соответствовать. По какой-то причине это не так. Допустим, это сводит меня с ума. Пожалуйста, помогите.