UICollectionView with zero cell spacing - ios

I've followed this answer and try to implement 5 cells per row and it's working great when I check on iPhone 6 & iPhone SE as below.
But the problem occures when I try to run it on iPhone 6 Plus. Can anyone help me out on figuring out the issue please?
This is my code.
screenSize = UIScreen.main.bounds
screenWidth = screenSize.width
screenHeight = screenSize.height
let itemWidth : CGFloat = (screenWidth / 5)
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.sectionInset = UIEdgeInsets(top: 10.0, left: 0, bottom: 10.0, right: 0)
collectionView!.collectionViewLayout = layout

It has to be
let itemWidth : CGFloat = (screenWidth / 5.0)
So the result will not be rounded.
Updated
Please make sure if you use storyboard to create your UICollectionView, remember to set autolayout to the collection view's size so that it is updated to whatever current screen size is.
Update 2
If you use storyboard there is no need to create a UICollectionViewFlowLayout. You can set the insets and spacings from storyboard.
Then in your .m file implement this to determine item's size.
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return yourDesiredSize;
}

To fix the blank spaces the size of each cell should be a round number. Then the difference between the sum of rounded numbers and the size of collectionView can be equally distributed or put in one cell.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// To avoid white space inbetween cells we're rounding the width of each cell
var width = CGFloat(floorf(Float(screenWidth/CGFloat(objects.count))))
if indexPath.row == 0 {
// Because we're rounding the width of each cell the cells don't cover the space completly, so we're making the first cell a few pixels wider to make sure we fill everything
width = screenWidth - CGFloat(objects.count-1)*width
}
return CGSize(width: width, height: collectionView.bounds.height)
}

Related

2 column collectionview sizing problem in some iphones

I am using this code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 50
let collectionViewSize = collectionView.frame.size.width - padding
return CGSize(width: collectionViewSize/2, height: collectionViewSize/2)
}
I am able to get a 2 column collection view on all iPhones except iPhone X and iphone XR, I don't know why
How to force 2 columns for all iPhones?
You can set layout of your collectionView by creating new layout and set it's itemSize, minimumInteritemSpacing and minimumLineSpacing and then assign new layout as collectionView.collectionViewLayout:
func setCollectionViewLayout(withPadding padding: CGFloat) {
let layout = UICollectionViewFlowLayout()
let size = (collectionView.frame.width - padding) / 2
layout.itemSize = CGSize(width: size, height: size)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView.collectionViewLayout = layout
}
and then call this method in viewDidLayoutSubviews (this is moment when frames are loaded and you can calculate with collectionView's frame)
override func viewDidLayoutSubviews() {
setCollectionViewLayout(withPadding: 50)
}
Note: I would recommend you to set leading and trailing constraints of collectionView to constant 25 instead of using padding
I suggest that you calculate width according to safeAreaLayoytGuide and, if you're using UICollectionViewFlowLayout, sectionInset. For UICollectionViewFlowLayout the following code will calculate proper width:
let sectionInset = (collectionViewLayout as! UICollectionViewFlowLayout).sectionInset
let width = collectionView.safeAreaLayoutGuide.layoutFrame.width
- sectionInset.left
- sectionInset.right
- collectionView.contentInset.left
- collectionView.contentInset.right
If you need two columns, than item width will be calculated like that:
let space: CGFloat = 10.0
let itemSize = CGSize(width: (width - space) / 2, height: 100 /*DESIRED HEIGHT*/)

How to properly size and center expanding cells in UICollectionView Swift 4.0

Note, I have scoured the internet and have not found a place to both size and centers cells that works. I tried doing it myself but I keep running to bugs I can't avoid. I am new to Swift. My code:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath:IndexPath) -> CGSize {
let cellWidth = collectionView.frame.size.width / 7.0
let cellHeight = collectionView.frame.height - 4.0
let imageSideLength = cellWidth < cellHeight ? cellWidth : cellHeight
return CGSize(width: imageSideLength, height: imageSideLength)
}
//centers the cells
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
// Make sure that the number of items is worth the computing effort.
guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout,
let dataSourceCount = photoCollectionView.dataSource?.collectionView(photoCollectionView, numberOfItemsInSection: section),
dataSourceCount > 0 else {
return .zero
}
let cellCount = CGFloat(dataSourceCount)
let itemSpacing = flowLayout.minimumInteritemSpacing
let cellWidth = flowLayout.itemSize.width + itemSpacing
let cellHeight = flowLayout.itemSize.height
var insets = flowLayout.sectionInset
// Make sure to remove the last item spacing or it will
// miscalculate the actual total width.
let totalCellWidth = (cellWidth * cellCount) - itemSpacing
let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right
let contentHeight = collectionView.frame.size.height
// If the number of cells that exist take up less room than the
// collection view width, then center the content with the appropriate insets.
// Otherwise return the default layout inset.
guard totalCellWidth < contentWidth else {
return insets
}
// Calculate the right amount of padding to center the cells.
let padding = (contentWidth - totalCellWidth) / 2.0
insets.left = padding
insets.right = padding
insets.top = (contentHeight - cellHeight) / 2.0
//insets.bottom = (contentHeight - cellHeight) / 2.0
return insets
}
}
I try to use two separate functions: the first to size the cells and the second to center the cells. (Note I only want new cells to expand horizontally, with a maximum of 6 cells.) However, my calculation of cell height and width in the 2nd function does not agree with how I set it in the first function, setting off a chain of issues. Any insight on how to both size and center the cells such that I can have 1-6 cells horizontally fit on my screen centered would be great.
Your layout calls are conflicting. Try following THIS Tutorial to get the hang of it.
Otherwise a good answer for this is HERE
var flowLayout: UICollectionViewFlowLayout {
let _flowLayout = UICollectionViewFlowLayout()
// edit properties here
_flowLayout.itemSize = CGSize(width: 98, height: 134)
_flowLayout.sectionInset = UIEdgeInsetsMake(0, 5, 0, 5)
_flowLayout.scrollDirection = UICollectionViewScrollDirection.horizontal
_flowLayout.minimumInteritemSpacing = 0.0
// edit properties here
return _flowLayout
}
Set it with:
self.collectionView.collectionViewLayout = flowLayout // after initializing it another way
// or
UICollectionView(frame: .zero, collectionViewLayout: flowLayout)

still got space when I set minSpace to 0 CollectionView cell

I now have a collectionView with 4 cells per row.
I've set layout like the following
let width = UIScreen.main.bounds.width / 4
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: width, height: width)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
self.module_CollectionView.collectionViewLayout = layout
which should give me a collectionView without any spacing between cells.
However, I still got very thin (looks like 1px) space between columns.
(please refer to the screen shot below)
It works fine if the cell width is 1/5 or 1/3 of Screen width.
I guess it's because the remainder or something ?
Would be good if someone could point out what might goes wrong.
thanks.
I think you might set wrong constraint, otherwise nothing is wrong in your code for flowlayout.
Now, first take one UIView in your collectionviewcell and set it's four constraint - top.leading,trailing,bottom with constant 0.
Then add your all the stuff (your views or images or buttons) in that view and give proper constraint.
You need to implement collectionView(_ collectionView: UICollectionView, layout collectionViewLayout:UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize.
In your case, the screen width is 375, and you want to divides it to 4 parts. If you directly divides 375 to 4 parts, you'll get 93.75, with decimal.
You should round it(decimal) to an integer like 94 + 94 + 94 + 93 = 375 instead of 93.75+93.75+93.75+93.75 = 375.
For Example:
override func viewDidLoad() {
super.viewDidLoad()
let screenWidth:Int = UIScreen.main.bounds.width
let parts:CGFloat = 4
var rounding:Int = 0
if(screenWidth.truncatingRemainder(dividingBy: parts) != 0) {
rounding = Int(screenWidth.truncatingRemainder(dividingBy: parts))
}
}
//----
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var roundingWidth = 0
if(rounding != 0) {
rounding -= 1
roundingWidth = 1
}
return CGSize(width: Int(screenWidth / parts) + roundingWidth, height: yourHeight)
}

Remove inset spacing at bottom of UICollectionView

I'm really in need of some help here. I've been trying for a few days but can't seem to fix it...
I'm trying to lay out images in a UICollectionView grid style, with scrolling disabled. So I have 4 images/cells, and I'm trying to completely fill the UICollectionView with these images with 1 spacing between them.
The problem, however is that the spacing between the cells is split between center and the bottom.
I've noticed that when changing the scrollDirection of the UICollectionView from vertical to horizontal, the problem still exists, but just changes direction too, so I'm guessing it has something to do with that.
example:
code:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if isInFeed && self.postImages!.count > 1 {
guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout else {
return CGSize()
}
flowLayout.minimumInteritemSpacing = 1
flowLayout.minimumLineSpacing = 1
switch (self.postImages!.count) {
case 2:
// we split the collectionView into 2 parts (+ 2*0.5 spacing)
return CGSize(width: (self.collectionView!.bounds.width/2)-CGFloat(0.5), height: self.collectionView!.bounds.height)
case 3:
// we split the collectionView into 3 parts, the first one taking up half, the other 2 images taking up 1/4th (+spacing)
if indexPath.row == 0 { return CGSize(width: (self.collectionView!.bounds.width/2)-CGFloat(0.5), height: self.collectionView!.bounds.height) }
else { return CGSize(width: (self.collectionView!.bounds.width/2)-CGFloat(0.5), height: (self.collectionView!.bounds.height/2)-CGFloat(0.5)) }
case 4:
// we split the collectionView into 4 parts (1/4th + spacing)
// if indexPath.section == 0 { return CGSize(width: (self.collectionView!.bounds.width/2)-CGFloat(0.5), height: (self.collectionView!.bounds.height/2)-CGFloat(1))}
// else {return CGSize(width: (self.collectionView!.bounds.width/2)-CGFloat(0.5), height: (self.collectionView!.bounds.height/2)-CGFloat(0))}
return CGSize(width: (self.collectionView!.bounds.width/2)-CGFloat(0.5), height: (self.collectionView!.bounds.height/2)-CGFloat(0.5))
default: break
}
}
// If not in Feed or just one image, take up entire collectionView
return CGSize(width: self.collectionView!.bounds.width, height: self.collectionView!.bounds.height)
}
I also tried subclassing UICollectionViewLayout and UICollectionViewFlowLayout, but without success, I've read Apple's documentation, but that doesn't seem to help much.
Hope this explains the problem clearly, I'd be happy to elaborate.
Have a great day!
Edit:
I changed the scroll direction from vertical to horizontal and added 2 extra calculated spacing to each cell just to show off what happens if I do that.
Edit 2:
Finally managed to fix it! (altough not as clean as I'd like it, it does work now)
I put the following code inside of the collectionViewLayout method:
if indexPath.section == 0 {
flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 1 * UIScreen.main.scale)
} else {
flowLayout.sectionInset = UIEdgeInsets.zero
}
Big thanks to everyone trying to help out!
The final solution that worked for me (for anyone that runs into a similar situation):
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
if section == 0 {
return UIEdgeInsetsMake(0, 0, 0, 1 * UIScreen.main.scale)
} else {
return UIEdgeInsets.zero
}
}
Try this code. Add in a function and call in view did load. You might need to make a little adjustments but it works in my case.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let width = UIScreen.main.bounds.width
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: width / 2, height: width / 2)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView!.collectionViewLayout = layout
In Storyboard try with Size Inspector with Minimum Spacing Zero and all Section Insects zero.
layout.minimumLineSpacing = 1.0f;
layout.minimumInteritemSpacing = 1.0f;
CGSize collectionSize = collectionView.frame.size;
CGFloat cellsPerRow = 2.0f;
CGFloat spacing = 0.5f;
CGFloat itemWidth = collectionSize.width/cellsPerRow - spacing;
CGFloat itemHeight = collectionSize.height/cellsPerRow - spacing;
return CGSizeMake(itemWidth,itemHeight);

How to display 3 cells per row in UICollectionView?

I used a custom flow layout according to this post.
Here is my implementation:
#implementation CustomLayout
-(void)prepareLayout{
[super prepareLayout];
// [self invalidateLayout];
if(self.collectionView){
CGSize newItemSize=self.itemSize;
// Number of items per row
int itemsPerRow=3;
float totalSpacing=self.minimumLineSpacing*(itemsPerRow-1);
newItemSize.width=(self.collectionView.bounds.size.width -totalSpacing)/itemsPerRow;
if(self.itemSize.height>0){
float itemAspectRatio=self.itemSize.width/self.itemSize.height;
newItemSize.height=newItemSize.width/itemAspectRatio;
}
[self setItemSize:newItemSize];
}
}
#end
This is what I've got:
What did I miss? I've come across some other SO posts but no luck so far.
Swift 3.0. Works for both horizontal and vertical scroll directions and variable spacing
Declare number of cells you want per row
let numberOfCellsPerRow: CGFloat = 3
Configure flowLayout to render specified numberOfCellsPerRow
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
let horizontalSpacing = flowLayout.scrollDirection == .vertical ? flowLayout.minimumInteritemSpacing : flowLayout.minimumLineSpacing
let cellWidth = (view.frame.width - max(0, numberOfCellsPerRow - 1)*horizontalSpacing)/numberOfCellsPerRow
flowLayout.itemSize = CGSize(width: cellWidth, height: cellWidth)
}
//Make use of UICollectionViewDelegateFlowLayout Protocol
class RVC: UICollectionViewController {
//some code
}
extension RVC: UICollectionViewDelegateFlowLayout{
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
var collectionViewSize = collectionView.frame.size
collectionViewSize.width = collectionViewSize.width/3.0 //Display Three elements in a row.
collectionViewSize.height = collectionViewSize.height/4.0
return collectionViewSize
}
For more information go through below link.
UICollectionView Set number of columns
itemSpacing = "Spacing size between cell."
itemsInOneLine = "Number of item which you want to display in single row."
collectionWidth = "Width of your collection view"
let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let width = (collectionWidth) - itemSpacing * CGFloat(itemsInOneLine - 1)
layout.itemSize = CGSize(width:floor(width/CGFloat(itemsInOneLine)),height:width/CGFloat(itemsInOneLine))
You don't have to do it by coding. You just have to do in xib.as per iPhone 5 or 5s width become 320. and you want to show 3 cells per row so u have to do 320/3 and as per you get whatever answer your cell size is as per result.If any doubt of my answer ask me.

Resources