Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import UIKit
import Cartography // https://github.com/robb/Cartography
/**
This is an example of self sizing `UICollectionView` cells using AutoLayout,
where the width of cells is always the width of the parent, to mimic `UITableView`.
*/
fileprivate let items: [String] = (0..<100)
.map { _ in Lorem.sentences(Int.random(min: 1, max: 8)) } // Using https://github.com/lukaskubanek/LoremSwiftum/blob/master/Sources/LoremSwiftum.swift
final class ViewController: UIViewController {
override func loadView() {
self.view = self.customView
}
private lazy var customView = View()
}
private final class View: UIView {
init() {
self.collectionView = UICollectionView(frame: .zero,
collectionViewLayout: self.layout)
super.init(frame: .zero)
self.collectionView.register(Cell.self, forCellWithReuseIdentifier: View.reuseIdentifier)
self.collectionView.dataSource = self
self.addSubview(self.collectionView)
constrain(self.collectionView, self) { view, superview in
view.edges == superview.edges
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let collectionView: UICollectionView
private let layout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.sectionInset = .zero
layout.estimatedItemSize = CGSize(width: 100, height: 100)
return layout
}()
var previousSize: CGSize?
override func layoutSubviews() {
super.layoutSubviews()
if let previousSize = self.previousSize, previousSize != .zero, previousSize != self.bounds.size {
// Need to invalidate layout AND reload data to make rotation work
self.layout.invalidateLayout()
self.collectionView.reloadData()
}
self.previousSize = self.bounds.size
}
fileprivate static let reuseIdentifier = "cell"
}
extension View: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: View.reuseIdentifier, for: indexPath) as! Cell
cell.text = items[indexPath.row]
cell.width = collectionView.bounds.size.width
return cell
}
}
private final class Cell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
self.contentView.addSubview(self.label)
self.contentView.backgroundColor = .orange
constrain(self.label, self.contentView, self) { label, superview, cell in
label.edges == inset(superview.edges, 10)
superview.center == cell.center
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var text: String = "" {
didSet {
self.label.text = self.text
self.setNeedsLayout()
}
}
var width: CGFloat = 0 {
didSet {
self.widthGroup = constrain(self.contentView, replace: self.widthGroup) { view in
view.width == self.width
}
}
}
private var widthGroup: ConstraintGroup!
private let label: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.textColor = .white
label.font = UIFont.preferredFont(forTextStyle: .body)
return label
}()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.