You must use UIAssortmentViewCompositionalFormat
for complicated layouts like this: this is a information.
I used to be capable of provide you with this end result:
MasonryLayoutViewController.swift
:
import UIKit
class MasonryLayoutViewController: UIViewController {
non-public let gadgets = Array(1...9)
non-public var collectionView: UICollectionView!
override func viewDidLoad() {
tremendous.viewDidLoad()
view.backgroundColor = .systemBackground
title = "Masonry Format"
collectionView = UICollectionView(
body: .zero,
collectionViewLayout: createMasonryLayout()
)
collectionView.backgroundColor = .systemBackground
collectionView.register(MasonryCell.self, forCellWithReuseIdentifier: MasonryCell.reuseIdentifier)
collectionView.dataSource = self
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
// MARK: - structure
non-public func createMasonryLayout() -> UICollectionViewLayout {
UICollectionViewCompositionalLayout { [weak self] (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in
guard let self = self else { return nil }
// variety of teams (every group has 3 gadgets)
let groupCount = Int(ceil(Double(self.gadgets.rely) / 3.0))
var teams: [NSCollectionLayoutGroup] = []
// alternate teams with totally different layouts
for i in 0.. NSCollectionLayoutGroup {
// huge merchandise occupies full width of group
let bigItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)
)
let bigItem = NSCollectionLayoutItem(layoutSize: bigItemSize)
let bigGroupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(2.0/3.0),
heightDimension: .fractionalHeight(1.0)
)
let bigGroup = NSCollectionLayoutGroup.vertical(
layoutSize: bigGroupSize,
subitems: [bigItem]
)
let smallItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.5)
)
let smallItem = NSCollectionLayoutItem(layoutSize: smallItemSize)
// group for 2 small gadgets, width is 1/3 of container
let smallGroupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0 / 3),
heightDimension: .fractionalHeight(1.0)
)
let smallGroup = NSCollectionLayoutGroup.vertical(
layoutSize: smallGroupSize,
subitems: [smallItem, smallItem]
)
// container group with horizontal structure
let containerSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(300)
)
let containerGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: containerSize,
subitems: [bigGroup, smallGroup]
)
return containerGroup
}
// group the place huge merchandise is on proper and small gadgets on left
non-public func makeBigRightGroup() -> NSCollectionLayoutGroup {
// small gadgets, every takes half peak
let smallItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.5)
)
let smallItem = NSCollectionLayoutItem(layoutSize: smallItemSize)
// group for 2 small gadgets, width is 1/3 of container
let smallGroupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1 / 3),
heightDimension: .fractionalHeight(1)
)
let smallGroup = NSCollectionLayoutGroup.vertical(
layoutSize: smallGroupSize,
subitems: [smallItem, smallItem]
)
// huge merchandise occupies full width of group
let bigItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(1)
)
let bigItem = NSCollectionLayoutItem(layoutSize: bigItemSize)
// group for large merchandise, width is 2/3 of container
let bigGroupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(2/3),
heightDimension: .fractionalHeight(1)
)
let bigGroup = NSCollectionLayoutGroup.vertical(
layoutSize: bigGroupSize,
subitems: [bigItem]
)
// container group with horizontal structure (small gadgets first, then huge merchandise)
let containerSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(300)
)
let containerGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: containerSize,
subitems: [smallGroup, bigGroup]
)
return containerGroup
}
}
// MARK: - UICollectionViewDataSource
extension MasonryLayoutViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection part: Int) -> Int {
return gadgets.rely
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: MasonryCell.reuseIdentifier,
for: indexPath
) as! MasonryCell
cell.configure(with: gadgets[indexPath.item])
return cell
}
}
MasonryCell.swift
:
import UIKit
class MasonryCell: UICollectionViewCell {
static let reuseIdentifier = "MasonryCell"
non-public let titleLabel: UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 22)
label.textColor = .white
label.textAlignment = .middle
return label
}()
override init(body: CGRect) {
tremendous.init(body: body)
contentView.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)
])
contentView.layer.cornerRadius = 8
contentView.layer.masksToBounds = true
contentView.backgroundColor = randomColor()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been applied")
}
func configure(with quantity: Int) {
titleLabel.textual content = "Factor (quantity)"
}
non-public func randomColor() -> UIColor {
let r = CGFloat.random(in: 0...1)
let g = CGFloat.random(in: 0...1)
let b = CGFloat.random(in: 0...1)
return UIColor(crimson: r, inexperienced: g, blue: b, alpha: 1)
}
}
A brief clarification:
-
Gadgets:
Every cell is represented by anNSCollectionLayoutItem
. In our structure, these things are the person cells you see. -
Teams:
Gadgets are mixed into teams. In our case, every “container group” is a horizontal group with a hard and fast peak (300 factors) that holds 3 gadgets organized in certainly one of two configurations:
In a “huge left” group, one huge merchandise (occupying 2/3 of the width) is positioned on the left, and a vertical subgroup (with two small gadgets, every taking half the peak) is on the best.
In a “huge proper” group, the structure is reversed: a vertical subgroup of two small gadgets (1/3 width) is on the left, and one huge merchandise (2/3 width) is on the best.
Every of those container teams is constructed utilizingNSCollectionLayoutGroup
(and might have nested teams for the small gadgets). -
Sections:
All container teams are then organized in a vertical outer group (one otherNSCollectionLayoutGroup
) that varieties the part. This outer group is created with a calculated peak based mostly on the variety of container teams plus spacing. Lastly, the part (anNSCollectionLayoutSection
) is returned by the structure supplier of theUICollectionViewCompositionalLayout
.