8

I have a UITableView loading a custom UITableViewCell from a XIB file. Everything is working fine, but my layout requires that the cells (all inside one single section) have spacing between them. Any chance this can be done without having to raise the ROW height?

how it is now
how it is now

how it's supossed to be
how it's supossed to be

EDIT:
this is how the code is today

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [[self.cards valueForKeyPath:@"cards"] count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    [ccTableView setBackgroundColor:[UIColor clearColor]];
    cardsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cardsCell"];

    if(cell == nil){
      NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"cardsCell" owner:self options:nil];
      cell = [topLevelObjects objectAtIndex:0];
    }

    NSString *nmCard = [[self.cards valueForKeyPath:@"cards.name"] objectAtIndex:indexPath.row];
    cell.descCardLabel.text = nmCard;

  return cell;
}
gmogames
  • 2,993
  • 1
  • 28
  • 40
  • Why don't you want to raise the row height? – Andy Obusek May 25 '12 at 22:28
  • @obuseme in the most simple case there's one xib and three row states (middle, top, bottom), the code will be quite entangled. – A-Live May 25 '12 at 22:31
  • @obuseme Also, my cell has a background image with 35 height where the label is. If I raise the row height, the layout will be how I want, but the tapping selection will work below the image, on the spacing, and I don't want accidentals selections of the wrong row. – gmogames May 25 '12 at 22:49
  • [Answer for Swift](http://stackoverflow.com/a/33931591/3681880) (One section per array element method) – Suragch Nov 26 '15 at 06:19

4 Answers4

37

There's actually a pretty easy solution to it that I found, if you're using custom uitableviewcell classes.

In the cell class, add this code:

- (void)setFrame:(CGRect)frame {
    frame.origin.y += 4;
    frame.size.height -= 2 * 4;
    [super setFrame:frame];
}

This will give you a 4pt buffer within the cell height you put into the uitablview class you are calling this cell in. Obviously, you now have to compensate for that less space in the cell when putting in labels and images, but it works. You can also do the same thing on the x-axis to make the width of the cell smaller. I've done this in my app to show background images behind my cells.

Anthony Agby
  • 371
  • 4
  • 6
  • Thank You that's the thing i looking for :) – Harshad Apr 22 '15 at 09:30
  • it's working; but auto layout damaged; i'm working on expandable cell; when press on cell to expand the expanded cell not adjusting all the text; can you advice – Sonic Feb 27 '16 at 21:27
7

If you can't change the cell's height, the solution is to use invisible intermediate cells of the required height. You'll need to recalculate indexes at table view delegate and datasource in that case.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *CELL_ID2 = @"SOME_STUPID_ID2";
    // even rows will be invisible
    if (indexPath.row % 2 == 1)
    {
        UITableViewCell * cell2 = [tableView dequeueReusableCellWithIdentifier:CELL_ID2];

        if (cell2 == nil)
        {
            cell2 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                          reuseIdentifier:CELL_ID2];
            [cell2.contentView setAlpha:0];
            [cell2 setUserInteractionEnabled:NO]; // prevent selection and other stuff
        }
        return cell2;
    }

    [ccTableView setBackgroundColor:[UIColor clearColor]];
    cardsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cardsCell"];

    if(cell == nil){
      NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"cardsCell" owner:self options:nil];
      cell = [topLevelObjects objectAtIndex:0];
    }

     // Use indexPath.row/2 instead of indexPath.row for the visible section to get the correct datasource index (number of rows is increased to add the invisible rows)
        NSString *nmCard = [[self.cards valueForKeyPath:@"cards.name"] objectAtIndex:(indexPath.row/2)];
        cell.descCardLabel.text = nmCard;

      return cell;
    }



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    // two times minus one (invisible at even rows => visibleCount == invisibleCount+1)
    return [[self.cards valueForKeyPath:@"cards"] count] * 2 - 1;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row % 2 == 1)
        return 40;
    return 162;
}

You will also need to recalculate the indexPath.row for :didSelectRowAtIndexPath: and other methods where it is used.

A-Live
  • 8,904
  • 2
  • 39
  • 74
  • any chance for a code example on how to accomplish this? I added my current code to the question. thanks. – gmogames May 25 '12 at 22:44
  • 1
    Actually, this only code made all even rows blank. For instance, the first row (cell 1) is returning 0, so instead of returning the cell with the text, it's returning the cell2 blank. so I get 2 items in the table but the 1st is blank. – gmogames May 25 '12 at 23:39
  • @Guilherme right, corrected it with `indexPath.row % 2 == 1`, by the even rows to be invisible i meant 2,4,6,... counting from 1. – A-Live May 25 '12 at 23:48
  • 1
    it worked! the only thing I added to the code was `[cell2 setUserInteractionEnabled:NO]` so touching is disabled for these cells. Thanks a lot for the help. – gmogames May 26 '12 at 00:07
  • This is easiest way,I found so far,but if you want to avoid overload of extra ones,try adding elements on UIView,instead directly in content view.Also,add constraints accordingly. – Rajal Jul 17 '15 at 10:19
4

Although @A-Live is technically correct, in order to prevent other issues, ex: you forget to put a indexPath.row/2 somewhere, you can do the following (which involves no programming):

Say for example your UITableViewCell height normally is 90 points and you want a 10 point spacing in between each cell. Make your UITableViewCell 100 points high and just make the bottom 10 points of the UITableViewCell blank (no objects of any sort). Then click the UITableViewCell in interface builder and set the backgroundColor to whatever you want the spacing area's color to be.

Voila! You got spacing in between each cell with a little work that is much easier than programming /2 everywhere!

SimplyKiwi
  • 12,376
  • 22
  • 105
  • 191
1

If you are looking for a solution in swift, this answer from reddit worked perfectly for me.

class CustomTableViewCell: UITableViewCell {
override var frame: CGRect {
    get {
        return super.frame
    }
    set (newFrame) {
        var frame =  newFrame
        frame.origin.y += 4
        frame.size.height -= 2 * 4
        super.frame = frame
    }
}
}
ArK
  • 20,698
  • 67
  • 109
  • 136
codewitch
  • 73
  • 5