Skip to content

Instantly share code, notes, and snippets.

@chosa91
Last active November 24, 2020 11:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chosa91/1e4e5048b696b39748ab76f14978ddff to your computer and use it in GitHub Desktop.
Save chosa91/1e4e5048b696b39748ab76f14978ddff to your computer and use it in GitHub Desktop.
Stackoverflow question: UICollectionViewCompositionalLayout multi column layout with auto-sizing cells - https://stackoverflow.com/a/64985964/2569338
/*
GOAL:
- UICollectionViewCompositionalLayout multi column layout with auto-sizing cells where each cell has the same height in a given row (uses the max cell height in a row)
REALITY:
- The groups aren't filled :/
*/
import Foundation
import UIKit
final class GridViewController: UIViewController {
private enum Section {
case main
}
private var dataSource: UICollectionViewDiffableDataSource<Section, Int>! = nil
private var collectionView: UICollectionView! = nil
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Grid"
configureHierarchy()
configureDataSource()
}
}
extension GridViewController {
private func createLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(44.0)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// Inner group
let innerGroupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(44.0)
)
let innerGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: innerGroupSize,
subitem: item,
count: 5
)
let outerGroupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(44.0)
)
let outerGroup = NSCollectionLayoutGroup.vertical(
layoutSize: outerGroupSize,
subitems: [innerGroup]
)
let section = NSCollectionLayoutSection(group: outerGroup)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
}
extension GridViewController {
private func configureHierarchy() {
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.backgroundColor = .black
view.addSubview(collectionView)
}
private func configureDataSource() {
let cellRegistration = UICollectionView.CellRegistration<TextCell, Int> { (cell, indexPath, identifier) in
// Populate the cell
let texts = [
String(identifier),
String.random(Int.random(in: 0...16))?.uppercased(),
]
cell.label.text = texts
.compactMap { $0 }
.joined(separator: "\n")
cell.layer.borderColor = UIColor.black.cgColor
cell.layer.borderWidth = 1
cell.label.textAlignment = .center
cell.label.font = UIFont.preferredFont(forTextStyle: .title1)
}
dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: collectionView) {
$0.dequeueConfiguredReusableCell(using: cellRegistration, for: $1, item: $2)
}
var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
snapshot.appendSections([.main])
snapshot.appendItems(Array(0..<94))
dataSource.apply(snapshot, animatingDifferences: false)
}
}
final class TextCell: UICollectionViewCell {
static let reuseIdentifier = "text-cell-reuse-identifier"
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.backgroundColor = UIColor.cornflowerBlue
configure()
}
required init?(coder: NSCoder) {
fatalError("not implemnted")
}
private func configure() {
label.translatesAutoresizingMaskIntoConstraints = false
// label.font = UIFont.monospacedDigitSystemFont(ofSize: 14, weight: .regular)
label.adjustsFontForContentSizeCategory = true
label.numberOfLines = 0
contentView.addSubview(label)
let inset = CGFloat(16)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: inset),
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -inset),
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: inset),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -inset)
])
}
}
extension String {
static func random(_ length: Int, minimumLength: Int = 0) -> String? {
guard length > 0 else { return nil }
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var randomString = ""
for _ in minimumLength..<length {
randomString.append(letters.randomElement()!)
}
return randomString
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment