Creating decoration view as custom column in UICollection View
Small trick we can use to get this.
Cell size
should be one - fifth
of ViewController
. So we can get 5 Cells in one row. U can create numberOfItems
what do u need.
Create and store seat number
in Dictionary
. So we can avoid reuse.
I have did sample for 48 number of seats.
Coding
var busSeatNumDict = [Int : String]()
var pathWayNumber = Int()
var seatNumer = Int()
override func viewDidLoad() {
super.viewDidLoad()
pathWayNumber = 2 // CENTER - PASSENGER CAN WALK
seatNumer = 1 // STARTING NUMBER
for i in 0...59
{
if i == pathWayNumber // If it s centre, values empty to dictionary
{
busSeatNumDict[i] = ""
pathWayNumber = pathWayNumber + 5 // Position empty - 2,7,12,17,22 ...... like that
}
else
{
busSeatNumDict[i] = String(seatNumer)
seatNumer = seatNumer + 1
}
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! RulesCollectionViewCell
cell.alpha = 0 // Initially alpha 0
let text = busSeatNumDict[indexPath.row]!
if text == "" || text == "2"
{
cell.alpha = 0
}
else
{
cell.alpha = 1
}
cell.backgroundColor = UIColor.clear
cell.layer.borderColor = UIColor(red: 83/255, green: 50/255, blue: 129/255, alpha: 1.0).cgColor
cell.layer.borderWidth = 1.0
cell.txtLbl.text = text
cell.txtLbl.textAlignment = .center
cell.txtLbl.textColor = UIColor.darkGray
cell.layer.cornerRadius = 5
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 60
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (self.collectionView?.frame.width)! / 5, height: (self.collectionView?.frame.width)! / 5)
}
Output
How To Achieve the desired Design in uicollection view using decorator view
You could do it like this,
- Create two different types of decoration view, one for vertical line which is at the center of the collection view and other being horizontal which appear below two cell
- Vertical decoration view is created only once for the whole view, while horizontal decoration view is created for a pair of two which appears below each row. For the last row, dont create the decoration view.
- subclass UICollectionViewFlowLayout, and override override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? and return appropriate decoration view.
Here is how the layout looks for me,
And here is the code used for that,
CollectionViewController,
class ViewController: UICollectionViewController {
let images = ["Apple", "Banana", "Grapes", "Mango", "Orange", "Strawberry"]
init() {
let collectionViewLayout = DecoratedFlowLayout()
collectionViewLayout.register(HorizontalLineDecorationView.self,
forDecorationViewOfKind: HorizontalLineDecorationView.decorationViewKind)
collectionViewLayout.register(VerticalLineDecorationView.self,
forDecorationViewOfKind: VerticalLineDecorationView.decorationViewKind)
super.init(collectionViewLayout: collectionViewLayout)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.white
collectionView?.register(CollectionViewCell.self,
forCellWithReuseIdentifier: CollectionViewCell.CellIdentifier)
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.CellIdentifier,
for: indexPath) as! CollectionViewCell
let name = images[indexPath.item]
cell.imageView.image = UIImage(named: "\(name).png")
cell.label.text = name
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return .zero
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10 + DecoratedFlowLayout.horizontalLineWidth
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (collectionView.bounds.size.width - DecoratedFlowLayout.verticalLineWidth) * 0.5
return CGSize(width: width,
height: width + 20)
}
}
CollectionViewCell,
class CollectionViewCell: UICollectionViewCell {
static let CellIdentifier = "CollectionViewCellIdentifier"
var imageView: UIImageView!
var label: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
createViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createViews() {
imageView = UIImageView(frame: .zero)
imageView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(imageView)
label = UILabel(frame: .zero)
label.font = UIFont.systemFont(ofSize: 20)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(label)
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
imageView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
imageView.rightAnchor.constraint(equalTo: contentView.rightAnchor),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
label.leftAnchor.constraint(equalTo: contentView.leftAnchor),
label.rightAnchor.constraint(equalTo: contentView.rightAnchor),
label.topAnchor.constraint(equalTo: imageView.bottomAnchor),
label.heightAnchor.constraint(equalToConstant: 20)
])
}
}
DecoratedFlowLayout,
class DecoratedFlowLayout: UICollectionViewFlowLayout {
static let verticalLineWidth: CGFloat = 20
static let horizontalLineWidth: CGFloat = 20
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
minimumLineSpacing = 40 // should be equal to or greater than horizontalLineWidth
}
override init() {
super.init()
minimumLineSpacing = 40
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributes = super.layoutAttributesForElements(in: rect) else {
return nil
}
var attributesCopy: [UICollectionViewLayoutAttributes] = []
for attribute in attributes {
attributesCopy += [attribute]
let indexPath = attribute.indexPath
if collectionView!.numberOfItems(inSection: indexPath.section) == 0 {
continue
}
let firstCell = IndexPath(item: 0,
section: indexPath.section)
let lastCell = IndexPath(item: collectionView!.numberOfItems(inSection: indexPath.section) - 1,
section: indexPath.section)
if let attributeForFirstItem = layoutAttributesForItem(at: firstCell),
let attributeForLastItem = layoutAttributesForItem(at: lastCell) {
let verticalLineDecorationView = UICollectionViewLayoutAttributes(forDecorationViewOfKind: VerticalLineDecorationView.decorationViewKind,
with: IndexPath(item: 0, section: indexPath.section))
let firstFrame = attributeForFirstItem.frame
let lastFrame = attributeForLastItem.frame
let frame = CGRect(x: collectionView!.bounds.midX - DecoratedFlowLayout.verticalLineWidth * 0.5,
y: firstFrame.minY,
width: DecoratedFlowLayout.verticalLineWidth,
height: lastFrame.maxY - firstFrame.minY)
verticalLineDecorationView.frame = frame
attributesCopy += [verticalLineDecorationView]
}
let contains = attributesCopy.contains { layoutAttribute in
layoutAttribute.indexPath == indexPath
&& layoutAttribute.representedElementKind == HorizontalLineDecorationView.decorationViewKind
}
let numberOfItemsInSection = collectionView!.numberOfItems(inSection: indexPath.section)
if indexPath.item % 2 == 0 && !contains && indexPath.item < numberOfItemsInSection - 2 {
let horizontalAttribute = UICollectionViewLayoutAttributes(forDecorationViewOfKind: HorizontalLineDecorationView.decorationViewKind,
with: indexPath)
let frame = CGRect(x: attribute.frame.minX,
y: attribute.frame.maxY + (minimumLineSpacing - DecoratedFlowLayout.horizontalLineWidth) * 0.5,
width: collectionView!.bounds.width,
height: DecoratedFlowLayout.horizontalLineWidth)
horizontalAttribute.frame = frame
attributesCopy += [horizontalAttribute]
}
}
return attributesCopy
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
And decoration views
class VerticalLineDecorationView: UICollectionReusableView {
static let decorationViewKind = "VerticalLineDecorationView"
let verticalInset: CGFloat = 40
let lineWidth: CGFloat = 4.0
let lineView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
lineView.backgroundColor = .black
addSubview(lineView)
lineView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
lineView.widthAnchor.constraint(equalToConstant: lineWidth),
lineView.topAnchor.constraint(equalTo: topAnchor, constant: verticalInset),
lineView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -verticalInset),
lineView.centerXAnchor.constraint(equalTo: centerXAnchor),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class HorizontalLineDecorationView: UICollectionReusableView {
let horizontalInset: CGFloat = 20
let lineWidth: CGFloat = 4.0
static let decorationViewKind = "HorizontalLineDecorationView"
let lineView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
lineView.backgroundColor = .black
addSubview(lineView)
lineView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
lineView.heightAnchor.constraint(equalToConstant: lineWidth),
lineView.leftAnchor.constraint(equalTo: leftAnchor, constant: horizontalInset),
lineView.rightAnchor.constraint(equalTo: rightAnchor, constant: -horizontalInset),
lineView.centerYAnchor.constraint(equalTo: centerYAnchor),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I hope you can make use of it and tweak values to suit your own need. Some of the calculations might make sense to change to some level. But, I hope you get the idea about how this could be achieved.
how to get the instance of the decoration view in the collection view?
Answer my own question!
Thanks for this article!
First, subclass UICollectionViewLayoutAttributes
and add any property you want.
Second, in the function layoutAttributesForDecorationViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes!
, set the property.
Third, in the UICollectionReusableView
class, override the function applyLayoutAttributes:
to get the custom UICollectionViewLayoutAttributes
instance that contains your property.
Done!
How to set each UICollectionView section in an individual column
I have it tried in UICollectionViewController
.
Click CollectionView
and change to CustomLayout
[UICollectionViewLayout]
UICollectionViewController
let values = [["a","b","c","d","e","f"], ["a","b","c"], ["a","b","c","d"], ["a","b","c","d","e","f"], ["a","b","c","d","e","f"],["a","b","c","d","e","f"], ["a","b","c"], ["a","b","c","d"], ["a","b","c","d","e","f"], ["a","b","c","d","e","f"]]
override func viewDidLoad() {
super.viewDidLoad()
let XIB = UINib.init(nibName: "RulesExrView", bundle: Bundle.main)
rulesCollexnVw.register(XIB, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerreuse")
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return values.count
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return values[section].count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! RulesCollectionViewCell
let text = values[indexPath.section][indexPath.item]
cell.backgroundColor = UIColor.clear
cell.layer.borderColor = UIColor(red: 81/255, green: 57/255, blue: 141/255, alpha: 1.0).cgColor
cell.layer.borderWidth = 1.0
cell.txtLbl.text = text
cell.txtLbl.textAlignment = .center
cell.txtLbl.textColor = .white
cell.layer.cornerRadius = 5
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("\n\n Selected indPath ", indexPath)
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
print("Kinddd ", kind)
switch kind {
case UICollectionElementKindSectionHeader:
if let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerreuse", for: indexPath) as? RulesReusableView {
// Configure Supplementary View
supplementaryView.backgroundColor = UIColor.clear
supplementaryView.headLbl.text = "Section \(indexPath.section)".uppercased()
supplementaryView.headLbl.textColor = UIColor.white
return supplementaryView
}
fatalError("Unable to Dequeue Reusable Supplementary View")
default:
assert(false, "Unexpected element kind")
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
print("Landscape")
rulesCollexnVw.reloadData()
} else {
print("Portrait")
rulesCollexnVw.reloadData()
}
}
UICollectionViewLayout [Not UICollectionViewFlowLayout]
class RulesLayout: UICollectionViewLayout {
let CELL_HEIGHT = 30.0
let CELL_WIDTH = 100.0
let horizontalSpacing = 5.0
let verticalSpaing = 5.0
let headerSpacing = 40.0
let STATUS_BAR = UIApplication.shared.statusBarFrame.height
var portrait_Ypos : Double = 0.0
var cellAttrsDictionary = Dictionary<IndexPath, UICollectionViewLayoutAttributes>()
var contentSize = CGSize.zero
var dataSourceDidUpdate = true
override var collectionViewContentSize : CGSize {
return self.contentSize
}
override func prepare() {
dataSourceDidUpdate = false
if UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight
{
if let sectionCount = collectionView?.numberOfSections, sectionCount > 0 {
for section in 0...sectionCount-1 {
let xPos = (Double(section) * CELL_WIDTH) + (Double(section) * horizontalSpacing)
var yPos : Double = 0.0
if let rowCount = collectionView?.numberOfItems(inSection: section), rowCount > 0 {
for item in 0...rowCount-1 {
let cellIndex = IndexPath(item: item, section: section)
if item == 0
{
portrait_Ypos = headerSpacing
}
else
{
portrait_Ypos = portrait_Ypos + CELL_HEIGHT + verticalSpaing
}
yPos = portrait_Ypos
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
// Determine zIndex based on cell type.
if section == 0 && item == 0 {
cellAttributes.zIndex = 4
} else if section == 0 {
cellAttributes.zIndex = 3
} else if item == 0 {
cellAttributes.zIndex = 2
} else {
cellAttributes.zIndex = 1
}
cellAttrsDictionary[cellIndex] = cellAttributes
}
}
}
}
let contentWidth = Double(collectionView!.numberOfSections) * CELL_WIDTH + (Double(collectionView!.numberOfSections - 1) * horizontalSpacing)
let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
print("self.contentSizeself.contentSize ", self.contentSize)
}
else
{
if let sectionCount = collectionView?.numberOfSections, sectionCount > 0 {
for section in 0...sectionCount-1 {
let xPos = (Double(UIScreen.main.bounds.width) - CELL_WIDTH) / 2.0
if let rowCount = collectionView?.numberOfItems(inSection: section), rowCount > 0 {
for item in 0...rowCount-1 {
let cellIndex = IndexPath(item: item, section: section)
if section != 0
{
if item == 0
{
portrait_Ypos = portrait_Ypos + CELL_HEIGHT + headerSpacing
}
else
{
portrait_Ypos = portrait_Ypos + CELL_HEIGHT + verticalSpaing
}
}
else
{
if item == 0
{
portrait_Ypos = headerSpacing
}
else
{
portrait_Ypos = portrait_Ypos + CELL_HEIGHT + verticalSpaing
}
}
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: portrait_Ypos, width: CELL_WIDTH, height: CELL_HEIGHT)
if section == 0 && item == 0 {
cellAttributes.zIndex = 4
} else if section == 0 {
cellAttributes.zIndex = 3
} else if item == 0 {
cellAttributes.zIndex = 2
} else {
cellAttributes.zIndex = 1
}
cellAttrsDictionary[cellIndex] = cellAttributes
}
}
}
}
let contentWidth = UIScreen.main.bounds.width
let contentHeight = CGFloat(portrait_Ypos) + CGFloat(CELL_HEIGHT)
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
print("sPort.contentSize ", self.contentSize)
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributesInRect = [UICollectionViewLayoutAttributes]()
for cellAttributes in cellAttrsDictionary.values {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
let celIndPth = cellAttributes.indexPath
if celIndPth.item == 0
{ // YOU HAVE TO ADD SUPPLEMENTARY HEADER TO THIS LAYOUT ATTRIBUTES
if let supplementaryAttributes = layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionHeader, at: cellAttributes.indexPath) {
attributesInRect.append(supplementaryAttributes)
}
}
}
}
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath]!
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
if elementKind == UICollectionElementKindSectionHeader {
let atts = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, with: indexPath)
if let itemAttributes = layoutAttributesForItem(at: indexPath) { // HERE WE HAVE TO SET FRAME FOR SUPPLEMENTARY VIEW
atts.frame = CGRect(x: itemAttributes.frame.origin.x,
y: itemAttributes.frame.origin.y - CGFloat(headerSpacing),width: itemAttributes.frame.width,height: CGFloat(headerSpacing))
return atts
}
}
return nil
}
}
XIB Subclass - [Collection Reusable View]
class RulesReusableView: UICollectionReusableView {
@IBOutlet weak var headLbl: UILabel!
}
UICollectionViewCell
class RulesCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var txtLbl: UILabel!
}
Portrait Output
Landscape Output
How to add a custom view after every 2 rows in a collectionView swift
My Code should be explanatory. I have set some values in viewdidload to get the kind of view you require.
import UIKit
class CollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@IBOutlet weak var collectionView : UICollectionView!
let totalProducts = 21
let columnsPerRow = 2
let addAfterRows = 2
var celltoShowWithAds = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let quot = (totalProducts/(columnsPerRow * addAfterRows))
print(quot)
celltoShowWithAds = totalProducts + quot + 1
collectionView.register(UINib(nibName: "CollectionItemCell", bundle: nil), forCellWithReuseIdentifier: "CollectionItemCell")
collectionView.register(UINib(nibName: "CollectionAdvertisementCell", bundle: nil), forCellWithReuseIdentifier: "CollectionAdvertisementCell")
collectionView.delegate = self
collectionView.dataSource = self
collectionView.reloadData()
//collectionView.backgroundColor = UIColor.blue
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return celltoShowWithAds
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row == 0{
let myCell:CollectionAdvertisementCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionAdvertisementCell", for: indexPath) as! CollectionAdvertisementCell
return myCell as CollectionAdvertisementCell;
}else if indexPath.row % 5 == 0{
let myCell:CollectionAdvertisementCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionAdvertisementCell", for: indexPath) as! CollectionAdvertisementCell
return myCell as CollectionAdvertisementCell;
}else{
let myCell:CollectionItemCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionItemCell", for: indexPath) as! CollectionItemCell
return myCell as CollectionItemCell;
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.row == 0{
return CGSize(width: view.frame.width, height: 0.0)
}else if indexPath.row % 5 == 0 {
return CGSize(width: view.frame.width, height: 80.0)
}else{
return CGSize(width: view.frame.width/CGFloat(columnsPerRow), height: 200.0)
}
}
//Use for interspacing
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
UICollectionView Custom Layout Middle column starting higher
The Collection view layout can be achieved by creating a custom layout class.
Theory:
Basically, collection view works directly with the custom layout object to manage the overall layout process, asking for the required layout information.
During the layout process, the collection view calls specific methods of the layout object. These methods provide a chance to calculate the position of items and to provide the collection view with the primary information it needs.
Following methods are always called in order during the layout process:
- prepare(): Perform the up-front calculations needed to provide layout information
- collectionViewContentSize: Return the overall size of the entire content area based on your initial calculations
- layoutAttributesForElements(in:): Return the attributes for cells and views that are in the specified rectangle
Related Topics
Nsnumber/Nsdecimalnumber Bizarre Behavior
Creating Decoration View as Custom Column in UIcollection View
Set Maximum Characters (To One) in a Nstextfield in Swift
Not Getting Screenlock Notification on Swift 4 on Mac
Swift Custom Response Serializer Is Returning Images at Random
Trim Video Always Fail When Use Avassetexportpresetpassthrough
Encode Struct and Convert to Dictionary [String: Any]
How to Convert a Pair of Bytes into a Float Using Swift
Swiftui Navigationview Starting Inside Itself
How to Get Window Reference (Cgwindow, Nswindow or Windowref) from Cgwindowid in Swift
How to Store Data from a Picker View in a Variable When a Button Is Pressed
Given a Swift 'Any' Type How to Determine If It's an 'Optional'
Programmatically Setting Texture in Scene Generated by Reality Composer
How to Detect Encoding in Data Based on a String
Midiclientcreate Does Not Work for 32 Bit Processors in Swift