Equal spacing around UICollectionViewCells - ios

I want to have equal amount of spacing between all the cells as well as between the screen border and the closest cell. Basically something like this. Equal spacing in and all around.
I managed to test this in the interface builder by setting values like this. I set the cell size to 110, Min spacing to 0 and all Section Insets to 10.
And it looks perfect in the IB.
However when I run it (in an iPad Air 2), it looks like this.
Notice the spacing in between the cells is bigger. I also tried to do this solely from the code by implementing the following methods from the UICollectionViewDelegateFlowLayout.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: 110, height: 110)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 0
}
That yielded the same results. Can anybody please tell me how to correct this? I'd prefer to do this by code. But I'm open to anything.

Unluckily, this is how UICollectionViewFlowLayout works by default. That's because you specify exact section insets but minimum interitem space.
To do what you're asking, you mainly have two ways to do it depending on the end result you wish for. Both have to be done manually by code.
• Enlarge the cells to leave the exact space (same space, bigger cells)
• Compute the space and change the insets to match it (same cells, bigger space)
Both can be done by either setting the values on the layout object (and invalidating it) or by returning the values through the delegate.

Related

iOS UICollectionView with self sizing items bug?

I'm trying to implement UICollectionView (flowLayout) with self sizing items.
Implementation is very simple - I have just set estimatedItemSize and set UICollectionViewCell constraints to manage it's size.
Everything works fine at first data reload after collectionView was created, but on another or some other reload few items at the top becomes same size as estimatedItemSize is. If scroll down and up - items size looks good again.
I have spend 2 days with this issue experimenting different cell constraints, trying to setNeedsLayout in various places and other stuff around collectionView. Is it bug?
In this post I had an interesting problem that I found my own answer to. There are two important functions to be using properly for the sizing purposes which are:
minimumInteritemSpacingForSectionAtIndex
insetForSectionAtIndex
sizeForItemAtIndexPath
Example of me using them in Swift
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionView, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 0, 0, 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let screenRect: CGRect = collectionView.bounds
let screenWidth: CGFloat = screenRect.size.width
let cellWidth: CGFloat = screenWidth / 24
//Replace the divisor with the column count requirement. Make sure to have it in float.
let size: CGSize = CGSize(width: cellWidth, height: cellWidth)
return size
}
The biggest secret is to be careful about attaching your views to the trailing edge and the bottom layout. If you only attach them to leading and the top, then you can set the width and height programmatically through frame or constraints. I think that doing it through constraints is a little more straight forward, though in my personal project I have chose to do it the other way because it makes the functionality slightly cleaner in my opinion.
Try to accomplish as much of a cells layout as possible inside of cellForItemAt.

Center UICollectionViewCells

I need to fix a small issue with my UICollectionView, when on the 6s device size I get a layout like this:
However, I want to know what is the best way to either center them so that its two lines, or should i shrink them down a bit so I can put three of them? I think I would prefer to center the two columns instead so I'm not cramming too much onto the same screen. I looked but wasn't sure what to do with the Layout formatting.
Thank you!
I believe one or both of these are what you are looking for. Play with the values you return and see what happens. Also, your constraint inside each cell will have some effect that I can not predict without seeing them.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionView, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return 0
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 0, 0, 0)
}

Adaptive UICollectionView Cell Width

I am new to collection view and Auto Layout and I have a problem making the cell sizes adapt to the various devices in the simulator. I am using the flow-layout and I set the sizes in the size inspector. The image I've provided shows the way I need the cells to look(canvas on the left iPhone5)on all devices. The iPhone4 display is good but the 6s is incorrect.
Can someone please show me how this is done as I cannot find the precise information I am looking for.
Thanks
Also, I'm not sure why the iPhone5 doesn't display the cells on the preview section like the 4&6 do..? any clues..?
screen shot1
With UICollectionView, you need to calculate the size of your cells, and the space around them (insets and interitem spacing) using delegate methods.
Something like this should work for you:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 8, left: 4, bottom: 0, right: 4)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return CGFloat(8)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let cellWidth = (view.bounds.size.width - 16) / 2
let cellHeight = cellWidth * 0.8 // multiply by some factor to make cell rectangular not square
return CGSize(width: cellWidth, height: cellHeight)
}
Within a UICollectionViewCell is where you would use Auto Layout to position the things in the cell, like labels, images, etc.

Placing the cells in a collection view in the centre rather than the outsides in swift

By default, a collection view will attempt to space out the cells in the collection by spacing them evenly so that there will be one cell touching either side of the collection view. Example:
But, when the cell is too wide to fit multiple cells in one row on the collection view, it will centre the cell in the collection view.
Is there a way to make the behaviour of centring cells, like in the 3rd picture, the default for the collection view so that there is 0 space between the individual cells and space on either side to the edges of the collection view?
Not that I'm aware of. You should implement something like this:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
CGFloat width = UIScreen.mainScreen().bounds.size.width
return CGSize(width, anyHeight)
}
and then implement the delegate method below as well:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsetsZero
}
Make sure to implement rotation handling too if it's applicable.
My answer would be to use a carefully set up something like
let insets = UIEdgeInsets(top: yourvalues, left: yourvalues, bottom: yourvalues, right: yourvalues),
and feed it to either YourCollectionView.contentInset, or
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return sectionInsets
}
This should work! Lemme know if you have any troubles with it!

UICollectionView spacing between rows becomes huge on certain devices

I have a collection view with the minimum spacing set to 10 for cells and lines. The horizontal space between the cells adjusts correctly, but I don't know how to alter the vertical spacing between the rows of cells. On the 6, which it was originally developed on, the space is negligible and works fine. But on every other device, the space quadruples in size for no apparent reason. Is there any way to set the spacing between the rows of cells to be a constant value across all devices?
Right now there isn't a way to set the size of collection view cells using AutoLayout. My guess is that the size of your cells just doesn't look good on other screen sizes, so you most likely will need to implement the UICollectionViewDelegateFlowLayout protocol (which extends the UICollectionViewDelegate protocol) and the func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize method.
Although if that's not the case maybe posting some screenshots would help.
Example method:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if(self.view.bounds.width > 400){
return CGSize(width:self.view.bounds.width/3-10, height:self.view.bounds.width/3-10)
}
return CGSize(width:self.view.bounds.width/2-10, height:self.view.bounds.width/2-10)
}

Resources