1

Updated: Sample project is github link

USE iPHONE 6 simulator

2 possible ways to achieve this bug. Just build and run and see. Or uncomment 256 row

//return CGSizeMake(widthAndHeight * self.venueLayoutZoom, widthAndHeight * self.venueLayoutZoom);

and press "Remove column" button

I have UICollectionView with a lot of UICollectionViewCells. My UI makes me to use zero space between cells. I have a pinch gesture in my UICollectionView. So sometimes sizeForItem:atIndexPath: returns me a big float numbers (like 11.821123411231). The problem is: If I don't round these floats I have a strange behaviour sometimes - enter image description here

It should be enter image description here

If I round up or down sizeForItem:atIndexPath: it looks great but there are spaces between cells enter image description here

I don't know what to do. It is really necessary to do without these spaces or strange cells. My flow layout is this

Controller Code:

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    CGFloat widthAndHeight = [self widthAndHeightForCollectionView:collectionView];
    CGFloat result = widthAndHeight * self.venueLayoutZoom;
    return CGSizeMake(result, result);
}

- (void)didReceivePinchGesture:(UIPinchGestureRecognizer *)gesture
{
    static CGFloat scaleStart;

    if (gesture.state == UIGestureRecognizerStateBegan) {
        scaleStart = self.venueLayoutZoom;
    }
    else if (gesture.state == UIGestureRecognizerStateChanged) {

        self.venueLayoutZoom = scaleStart * gesture.scale;
    }
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    VenueLayoutCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kVenueLayoutCellReuseIdentifier forIndexPath:indexPath];

    self.activeCollectionViewCellsDictionary[indexPath] = cell;
    if (self.activeCollectionViewObjects.count > indexPath.section) {
        NSArray *rows = self.activeCollectionViewObjects[indexPath.section];
        if (rows.count > indexPath.row) {
            if ([rows[indexPath.row] isKindOfClass:[VenueLayoutCellObject class]]) {
                VenueLayoutCellObject *object = rows[indexPath.row];
                cell.cellObject = object;

            }
        }
    }
    return cell;
}

Cell Code:

@property (nonatomic, strong) CALayer *circularLayer;

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self allocAndAddLayers];
}

- (void)allocAndAddLayers
{
    self.circularLayer = [CALayer layer];
    [self.layer addSublayer:self.circularLayer];
}

#pragma mark - Property Set

- (void)setCellObject:(VenueLayoutCellObject *)cellObject
{
    self->_cellObject = cellObject;
    self.objectBackgroundColor = cellObject.objectColor;
    self.type = cellObject.type;
}

- (void)prepareForReuse
{
    [self.circularLayer removeFromSuperlayer];
    [self allocAndAddLayers];
}

- (void)setType:(VenueLayoutObjectType)type
{
    self->_type = type;
    [self updateInderfaceDependOnType];
}

- (void)layoutSubviews
{
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    [self updateRoundedCorners];
    [CATransaction commit];
    [super layoutSubviews];
}

- (void)updateRoundedCorners
{
    CGRect bounds = self.bounds;
    CGRect frame = self.frame;
    self.circularLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
}

- (void)setLayerBackgroundColor:(UIColor *)color
{
    self.circularLayer.backgroundColor = color.CGColor;
    self.objectMaskLayer.strokeColor = color.CGColor;
    self.deselectedColor = color;
}

- (void)updateInderfaceDependOnType
{
    UIColor *tempObjectColor = [UIColor grayColor];
    UIColor *objectColor = self.objectBackgroundColor ? : tempObjectColor;
    [self setLayerBackgroundColor:objectColor];
}

Updated Code:

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    CGFloat widthAndHeight = self.widthAndHeightForActiveCollectionView;
    CGFloat result = lroundf(widthAndHeight * self.venueLayoutZoom);
    CGFloat width = result;
    if (indexPath.row > self.increasedWidthInitialIndex) {
        width++;
    }
    return CGSizeMake(width, result);
}

CGFloat widthAndHeight = CGRectGetWidth(self.activeCollectionView.bounds) / maxCount;
    NSNumber *widthNumber = @(CGRectGetWidth(self.activeCollectionView.bounds));
    NSInteger count = widthNumber.integerValue % maxCount;
    maxCount--;
    self.increasedWidthInitialIndex = maxCount - count;

Updated: If I use low item size (e.g CGSizeMake(7.f, 7.f)) cells doesn't fit whole collection view but space still exists

Artem Z.
  • 1,243
  • 2
  • 14
  • 36

1 Answers1

1

Eventually setting width / height to half pixels changes the scale according to the device pixel depth (retina vs non-retina) - more info here

When you try and divide your screen to non-whole numbers, i.e. for screen width of 320 create 6 cells of 53.3 with might cause the UI to break.

You should try and find the remainder of your devision, i.e:

320 % 6 -> 2

And then make 2 cells 1 pixel wider. So instead of 6 cells consisting of 53.3 pixels wide, you will have 2 consisting of 54 and 4 more of 53, then everything will fit correctly.

EDIT:

After going over your project, I have added printouts of your collection see what issues could be caused by widths, Iv'e added this method in the ViewController.m:

- (void)printoutGrid
{
    NSLog(@"collectionview bounds: %f, %@", self.activeCollectionView.bounds.size.width, NSStringFromCGSize(self.activeCollectionView.contentSize));
    CGFloat calculatedWidth = [self widthAndHeightForActiveCollectionViewItem];
    CGFloat result = floor(calculatedWidth * self.venueLayoutZoom);

    for (int rowAt = 0; rowAt < self.activeCollectionViewObjects.count; rowAt++)
    {
        NSArray* arrayAt = self.activeCollectionViewObjects[rowAt];
        NSString* rowString = @"|";

        for (int colAt = 0; colAt < arrayAt.count; colAt++)
        {
            if (colAt > self.increasedWidthInitialIndex)
            {
                rowString = [rowString stringByAppendingString:[NSString stringWithFormat:@"%d|", (int)result + 1]];
            }
            else
            {
                rowString = [rowString stringByAppendingString:[NSString stringWithFormat:@"%d|", (int)result]];
            }
        }

        NSLog(@"%@", rowString);
    }
}

And called it after every time you reload the collection or invalidate the layout, Iv'e found only that you should use floor instead of lroundf.

This method will help you debug your widths for the future.

But, after going over your project settings, something seemed off in your simulator, I noticed it was too large / out of scale and not retina, I went to your project settings and saw that your project is not retina compatible - which means the UI will not use Auto-Scaling -> which means it will use the same resolution (320 x 518) for all devices and what it does, it stretches the UI - meaning in iPhone 6 it multiplies it, and the stretching is being anti-analysed, which causes these so-called empty spaces between cells even though there is not space there.

What you need to do, is go to your project settings -> and in general scroll down to "Launch Screen File" and select "LaunchScreen" from the list:

enter image description here

This seems to solve the issue for this project. Let me know if you have anymore question and if it works.

Please note - it will require you to change size calculation a-bit because the resolution changes again after "viewDidLayoutSubviews" and not only when the view loads.

Good luck!

unkgd
  • 671
  • 3
  • 12
  • Thanks for your reply. Not working :( and what should I do if my zoom value is 1.2311231 eg – Artem Z. Jul 27 '17 at 13:55
  • Can you show me your updated code for the sizeForItem that didn't work? – unkgd Jul 27 '17 at 14:00
  • I've updated my question. In my example I have 29 items in one row. Width is 320. 11 - is rounded width. 11 * 28 + 12 = 320 – Artem Z. Jul 27 '17 at 14:05
  • And what is the result? you still have spaces? or something else? – unkgd Jul 27 '17 at 14:24
  • Ye, still got 1 space. And if I zoom - spaces still exist – Artem Z. Jul 27 '17 at 14:47
  • and if my zoom is 3.1924182096736713 and I have to calculate size - 3.1924182096736713 * 320 = 1021.5738270955749. 1021.5738270955749 % 29 = not integer value – Artem Z. Jul 27 '17 at 15:12
  • Man, check an updated question. It's so strange. Help me out please – Artem Z. Jul 28 '17 at 14:01
  • Is there any change you can post some kind of link to your actual code which displays this collection? something that compiles, because its hard to understand wether the collection is spread across a scroll view and then you need to consider the contentsize or the screen size – unkgd Jul 30 '17 at 06:21
  • I've done change any kind of code. Problem still exists, help me out – Artem Z. Jul 30 '17 at 21:52
  • In order to help you I need the complete code - i.e. what is widthAndHeightForCollectionView, how do you zoom etc, if you can provider a stripped version of your source code I'll go over it to find whats wrong – unkgd Jul 31 '17 at 07:27
  • @ArtemZ. Iv'e edited my answer with a solution for you. Good luck :) – unkgd Jul 31 '17 at 13:52
  • yes, I know this about LaunchScreen. But in my app I have to do blank LaunchImage like that. Thanks for your help, but it isn't solution for me :( – Artem Z. Jul 31 '17 at 14:02
  • You do have a LaunchScreen black image - just put it onto the LaunchScreen.Storyboard - it will still be black it doesn't change anything for you, without using launch screen it will keep having the blank lines because it will keep stretching the UI in weird ways that you can't really control, as you can also see in this discussion: https://stackoverflow.com/questions/32796924/my-app-on-iphone-6-6s-6p-and-6sp-is-stretched-after-upgrade-to-ios9 and here: https://stackoverflow.com/questions/25754942/how-to-enable-native-resolution-for-apps-on-iphone-6-and-6-plus – unkgd Jul 31 '17 at 14:11
  • Actually I have to use this from the same UI for all screens. This is the client's desire – Artem Z. Jul 31 '17 at 14:22
  • You can still do it, just use constraints correctly, it will probably be more work, but as far as I know, this is the only way to prevent this problem, because in different zooms, it might stretch 1/2 pixel on each side and cause a gap, the calculations seem correct. Another "hack" is giving each cell 1 more pixel of width, but this might still re-occur – unkgd Jul 31 '17 at 14:24
  • btw Thanks for your help. I will leave this question without answer. If nobody replies - I will accept your answer. Thanks. – Artem Z. Jul 31 '17 at 14:31