'how should the math of UICollectionViewFlowLayout spacing work?
I'd like someone could explain clearly how I should calculate the math for the UICollectionViewFlowLayout, exactly "the subtract spacing" thing from itemSize width/height. in this example I get a squared view, 3 items in 3 columns.
- why if I use
width: (view.frame.width/3)-testSpacing-1.5
the grid gives standard two columns and empty at the center? and if is use:
width: (view.frame.width/3)-testSpacing-6
nothing seems to change?
Am I doing it right? but why someone told me I should subtract half of the spacing and not the whole value?
Is it normal that if I rotate device the space between cells becomes greater? is there a "pattern" to manage that thing?
var collectionData = ["1🐶", "2🐱", "3 🐼", "4🐯", "5🐙", "6🦕", "7🦖", "8🦀", "9🐬", "10🦋", "11🐠", "12🦇","1🐶", "2🐱", "3 🐼", "4🐯", "5🐙", "6🦕", "7🦖", "8🦀", "9🐬", "10🦋", "11🐠", "12🦇"]
let testSpacing: CGFloat = 2
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(
width: (view.frame.width/3)-testSpacing-5,
height: (view.frame.width/3)-testSpacing-5)
layout.minimumInteritemSpacing = 5
layout.minimumLineSpacing = 5
layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
myCollectionView.collectionViewLayout = layout
my cell:
class Test_CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var messageLabel: UILabel!
static let identifier = "Test_CollectionViewCell"
private var message: String = "" {
didSet {
self.messageLabel.text = message
}
}
func setup(message: String) {
self.backgroundColor = .systemTeal
self.messageLabel.backgroundColor = .white
if message == "1🐶" {
self.messageLabel.backgroundColor = .red
}
self.message = message
// contentView.clipsToBounds = true
}
override func prepareForReuse() {
self.backgroundColor = .white
self.messageLabel.backgroundColor = .white
}
}
Solution 1:[1]
In short, when you write this code (view.frame.width/3)-testSpacing-1.5
and then this (view.frame.width/3)-testSpacing-6
in both cases, you do not have enough room in the same row to add 3 cells and hence why you see no significant differences
Let's take an example with some math for the horizontal calculation you use
- Let's say the value of
view.frame.width
was375
. view.frame.width/3
=125
125 - testSpacing(2) - 1.5
=121.5
which is your cell width- Now you had 2 edge insets set of
5
each which makes a total of10
- Plus you have a
minimumInteritemSpacing
between each cell set to 5 which makes a total of10
since there are 2 gaps between the cells in a 3 column layout
- So let's add all the spacing up now: Since you expect 3 cells
cell width(121.5 * 3) + cell spacing(10) + insets(10) = 384.5
- Compare the value in point 6 with point 1, clearly
384.5 > 375
which means the width taken by 3 cells, spacing and inset is more than the width of the collection view and hence collection view cannot fit your 3 columns and goes with 2 - Since it goes with 2, the calculation becomes
cell width(121.5 * 2) + cell spacing(10) + insets(10) = 263
- Since the collection view's width is 375, there is excess space of
375 - 263 = 112
which is the hole you see in the middle - You set the
minimumInteritemSpacing
to 5 which is the minimum, the max can be anything so the gap between the cells or hole you see is the 112
I hope this explains the results you see, now let's try to create a layout with the columns we want (assuming a vertical scrolling collection view)
A good idea when setting up a collection view is to figure out the available width we have to work with. This is the width of the collection view - (inter cell spacing + edge insets)
We then take this available width and divide it by the number of columns we want to see.
Let's start with code for a 3 columns layout:
private func createLayout() -> UICollectionViewFlowLayout
{
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
// Padding on the left and right between the cells
// and the collection view boundary
let horizontalInsets: CGFloat = 5
// How many columns we want
let numberOfColumns = 3
// Spacing we want between our cells
let cellSpacing: CGFloat = 10
// Since the collection view is width of the whole screen,
// the available width for your cells is the width of the screen
// minus the insets which are the padding on the left and right
var availableWidth = UIScreen.main.bounds.width - (horizontalInsets * 2)
// A 3 column layout will have 2 spaces between the cells
// Between cell 1 - 2 and between cell 2 - 3
// A 4 column layout will have 3 spaces between the cells
// Cell 1 - 2, Cell 2 - 3 and Cell 3 - 4
// So the number of spaces will be numberOfColumns - 1
// We need to adjust the available width based on the spaces we want
// between our cells
availableWidth -= (cellSpacing * CGFloat(numberOfColumns - 1))
// Calculate the cell width based on the space we have available
cellWidth = availableWidth / CGFloat(numberOfColumns)
layout.itemSize = CGSize(
width: cellWidth,
height: cellWidth)
// Set the minimum between the cell spacing setting and 5
// as the minimum spacing between items
layout.minimumInteritemSpacing = min(cellSpacing, 5)
layout.minimumLineSpacing = 5
layout.sectionInset = UIEdgeInsets(top: 0,
left: horizontalInsets,
bottom: 0,
right: horizontalInsets)
return layout
}
I have left some comments in the code explaining some calculations, this is the output:
Notice the values of the different items
Now since my starting point is to determine the available width, changing the number of columns I want is simple, just change this line to 4
// How many columns we want
let numberOfColumns = 4
The output you get is:
Let's say you want to decrease the spacing between cells to 0 and keep only the insets, just change the cellSpacing to 0
// Spacing we want between our cells
let cellSpacing: CGFloat = 0
The result:
The key is finding out the total available space using the formula above and then calculate the cell width.
Ofcourse, the same can be applied for vertical spacing with some adjustments.
I hope this helped and gives you some insight into the calculations and results you were seeing with some ideas on getting your desired layout.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |