Setting size of UICollectionViewCell in a way that there is no interim spacing in between
Asked Answered
F

4

0

I'm using an UICollectionView on which I want to place seven cells side by side. The whole screen should be used for this. Currently, I'm using the width of the collection view and divide it by seven. Now I get an item width of 45.71429 on an iPhone 4. Between some cells there is an interim spacing. How can I handle this? I want to fill out the whole screen and all items should have the same size.

One option which comes to my mind is to round the value and use the remaining value as inset. But isn't there a better way?

Fester answered 6/3, 2015 at 11:44 Comment(5)
See this,https://mcmap.net/q/122085/-uicollectionview-cell-spacing-based-on-device-screen-sizeVermilion
You can use integer values for width of cell, calculate extra points and apply it to one of the cell using flow layoutWayward
@ZaidPathan: I tried that. I thought I could use no spacing between cells, but it seems it isn't possible.Fester
@aquarium_moose: But to which cell? The cells should have the same size. The only way I found is to set an inset on the outside.Fester
@testing, You can spread between all cells, the difference will be just in 1 point, nobody will see it ) Insets good solution, but anyway they will be different tooWayward
V
2

Step 1: Implement UICollectionViewDelegateFlowLayout(if not done).

Step 2: Use delegate method of UICollectionViewDelegateFlowLayout.

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
return CGSizeMake((UIScreen.mainScreen().bounds.width)/7,120); //use height whatever you wants.
}

Step 3: Go to XIB or StoryBoard where you have your CollectionView.

Step 4: In XIB or StoryBoard where you have your CollectionView, click on CollectionView.

Step 5: Go to InterfaceBuilder, then in second last tab (ie: Size Inspector) set Min Spacing

For Cells = 0

For Lines = 0

That it.

Vermilion answered 11/3, 2015 at 10:6 Comment(8)
I assume that minimumLineSpacing and minimumInteritemSpacing are the same as you write Cells/Lines = 0. I have my CollectionView created in code. The spacing between the cells seems to differ in simulator.Fester
That might be AutoLayout issue, did you set constraints to cell width?Vermilion
I'm using a label which I positioned with Auto Layout in the middle of the cell. But I'm not using Auto Layout for the cell width.Fester
so what is width of that label.? Is it has fixed width or you have pinned it.?Vermilion
It should be the intrinsic content size. I only used center X and center Y for the auto layout constraint to position it. Now I tried to not adding the label with the same result. The spacing is not an integer value. I think that is the reason why this happens.Fester
once remove that label and just test it, see what happens.Vermilion
I tried that but it is the same result. Two cells have a spacing on the side and the other not.Fester
Let us continue this discussion in chat.Vermilion
P
2

Try this!

Most importantly add UICollectionViewDelegateFlowLayout and UICollectionViewDelegate to your controller

Implement below methods for inset and sizeForItem for your cell size.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0, 0, 0, 0)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // Here, I need 3 equal cells occupying whole screen width so i divided it by 3.0. You can use as per your need.
    return CGSize(width: UIScreen.main.bounds.size.width/3.0, height: UIScreen.main.bounds.size.width/3.0)                
}

For 0 spacing between cells, we need to specify it’s layout like this.

let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
self.collectionView!.collectionViewLayout = layout

Thanks. Hope this helps!

Paestum answered 16/6, 2018 at 10:11 Comment(0)
C
1

As you already figured out it's impossible to divide a 320 point wide screen into 7 equal portions.

But if a cell is a half or even one point larger or smaller than another one nobody will notice. You can use a little bit of math to get integer pixel values (i.e. 0.5 points).

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    var size: CGSize!
    let column = indexPath.item % 7
    let width = collectionView.bounds.size.width
    let height = 80.0

    if width == 320.0 {
        // iPhone 5
        // 46 + 0,5 + 45 + 0,5 + 45 + 0,5 + 45 + 0,5 + 45 + 0,5 + 45 + 0,5 + 46
        if column == 0 || column == 6 {
            size = CGSize(width: 46, height: height)
        }
        else {
            size = CGSize(width: 45, height: height)
        }
    }
    else if width == 375.0 {
        // iPhone 6
        // 53 + 0,5 + 53 + 0,5 + 53 + 0,5 + 54 + 0,5 + 53 + 0,5 + 53 + 0,5 + 53
        if column == 3 {
            size = CGSize(width: 54, height: height)
        }
        else {
            size = CGSize(width: 53, height: height)
        }
    }
    else if width == 414.0 {
        // iPhone 6 Plus
        // 58 + 0,5 + 59 + 0,5 + 59 + 0,5 + 59 + 0,5 + 59 + 0,5 + 59 + 0,5 + 58
        if column == 0 || column == 6 {
            size = CGSize(width: 58, height: height)
        }
        else {
            size = CGSize(width: 59, height: height)
        }
    }
    else {
        println("Unhandled Width: \(width)")
        abort()
    }
    return size
}

That's just an example, that I had ready because I am currently working on a calendar view. It has a 1 pixel spacing between each cell. For a 320 pt wide cell layout without spacing you could use something like 45.5+45.5+46+46+46+45.5+45.5

Chord answered 11/3, 2015 at 10:9 Comment(3)
Wow! The smallest spacing possible! Instead of aborting I'd suggest to use size=width/7. The only disadvantages I could see here, would be if a new screen width is introduced and you have to adapt it for each screen (e.g. iPad). But I think that is as close as one could get.Fester
Yes, in production code one should replace the else { abort() } with width / 7. It might look ugly, but only until you release the next update.Chord
One more thing to add: On orientation change you also have to specify the sizes like in your example.Fester
S
0

Try this out, declare these variables

  NSInteger insets_Top=5;
  NSInteger insets_Bottom=5;
  NSInteger insets_Left=5;
  NSInteger insets_Right=5; 

and add these methods

 - (CGSize)collectionView:(UICollectionView *)collectionView layout:   (UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:   (NSIndexPath *)indexPath
{
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    CGFloat screenWidth = screenRect.size.width;
    CGSize img_size=CGSizeMake(screenWidth/num_items-   (insets_Right+insets_Left), screenWidth/num_items);
    return img_size;
}

  - (UIEdgeInsets)collectionView:
 (UICollectionView *)collectionView layout:  (UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:  (NSInteger)section
   {
      return    UIEdgeInsetsMake(insets_Top,insets_Left,insets_Bottom,insets_Right);
   }

Here num_items=7 as in your case you want number of cells in a row to be 7

Stick answered 7/3, 2015 at 11:24 Comment(3)
I had to take num_items=6 to get seven cells in a row. Shouldn't it be screenHeight for img_size as the second parameter? As I can see I still have a spacing between the cells. Is this the only way?Fester
No, to get 7 cells in a row num_items=7 ; and YES the second parameter could be screenHeight if you dont want square cells.Stick
I had minimumLineSpacing and minimumInteritemSpacing set to zero. Perhaps that is the reason why he showed me one more cell.Fester

© 2022 - 2024 — McMap. All rights reserved.