Last active
November 24, 2020 11:55
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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