5

I am targeting iOS 7 and 8, and I want to eliminate the margin appearing on the left side of the images in this UITableView below. I would even be willing to accept a solution that only works on iOS 8 if the solution is simple/elegant. (I would just live with the margin on iOS 7 as it dies out).

This is what I would like it to look like:

I have read through many similar questions on Stack Overflow (such as this one), or ones specific to grouped UITableViews (here and here), but cannot seem to get any to work quite right.

For example, if I try to solve the problem using contentInset (a common answer on SO):

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, -16, self.tableView.contentInset.bottom, self.tableView.contentInset.right);
    self.tableView.separatorInset = UIEdgeInsetsMake(0, 33, 0, 0);
}

Then I end up with the gap on the right side of the tableview:

I get why it's happening, the entire tableview is just shifted over, as seen in the Debug View Hierarchy screen:

However, I've tried adjusting the tableView frame size to compensate, but it never seems to work correctly. Plus this seems hacky; there must be a better way.

For the record, here's my cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // get a cell that we can use]
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"VideoCell" forIndexPath:indexPath];

    cell.textLabel.numberOfLines = 0;

    cell.selectedBackgroundView = selectionColor;

    cell.accessoryView = [[UIImageView alloc] initWithImage:[PTStyleKit imageOfArrow]];

    // Create the attributed string (text + attributes)
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:[videos objectAtIndex:indexPath.row] attributes:attributes];

    // Set it in our UILabel and we are done!
    [cell.textLabel setAttributedText:attributedText];

    NSString* filename = [filenames objectAtIndex:indexPath.row];
    if (filename == nil)
    {
        filename = cell.textLabel.text;
    }

    UIImage *imageOne = [UIImage imageNamed:[NSString stringWithFormat:@"medium-%@", filename]];
    cell.imageView.image = [UIImage imageWithCGImage:imageOne.CGImage scale:imageOne.size.height/44 orientation:imageOne.imageOrientation];

    return cell;
}
Ben
  • 54,723
  • 49
  • 178
  • 224
Mason G. Zhwiti
  • 6,444
  • 11
  • 61
  • 97
  • 1
    looks like it's a problem with tableviewcell and not tableview itself. Can you also post your `cellForRowAtIndexPath:` method? – Novarg Jan 14 '15 at 07:40
  • Thanks for taking a look @Novarg, just added it. – Mason G. Zhwiti Jan 14 '15 at 07:43
  • can you also debug that method and log the position of the `cell.imageView`? – Novarg Jan 14 '15 at 07:47
  • @Novarg I am seeing x:0.000000, y: 0.000000 when I do `NSLog(@"x: %f, y: %f", cell.imageView.frame.origin.x, cell.imageView.frame.origin.y);`. Is that what you mean? – Mason G. Zhwiti Jan 14 '15 at 08:14
  • @Novarg If you're noticing the strange small images being shown in the debug view hierarchy, I had assumed that was just a bug in Xcode 6.1.1, as they don't look that small/misplaced in the simulator. – Mason G. Zhwiti Jan 14 '15 at 08:15
  • Yes, that's what I meant. I was thinking that those coordinates were not 0, but now I do not have any idea how to fix it – Novarg Jan 14 '15 at 08:40
  • 1
    You can allways make a custom cell with nib and from there things are easier and much customizable than using default UITableviewCell – Silviu St Jan 14 '15 at 10:18

6 Answers6

5

Set a clear background to your table view and set thecontentInset property.

Code:

tableView.contentInset = UIEdgeInsetsMake(0, -15, 0, 0);
tableView.backgroundColor = [UIColor clearColor];

but increase the width of the table view by 15 pixels by setting the frame.

Ashok Londhe
  • 1,491
  • 11
  • 29
user1122069
  • 1,767
  • 1
  • 24
  • 52
5

1. On iOS 13

The key is, together with other things, to set cell.contentView.layoutMargins to .zero:

/// view controller
...
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "identifier")
tableView.separatorInset = .zero
tableView.directionalLayoutMargins = .zero
tableView.layoutMargins = .zero
...

/// data source
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "identifier")!
    cell.textLabel?.text = "Text"
    cell.directionalLayoutMargins = .zero
    cell.layoutMargins = .zero
    cell.contentView.directionalLayoutMargins = .zero
    cell.contentView.layoutMargins = .zero
    return cell
}

If you are utilizing UITableViewController, in addition to all the above you also need to apply this:

tableViewController.viewRespectsSystemMinimumLayoutMargins = false

2. On iOS 12 and lower

It seems that there is no way to use layoutMargins etc. to place the standard UITableViewCell.textLabel to zero offset in relation to the table. The easiest and the only way I found is to subclass the cell and override layoutSubviews like this:

class MyCell: UITableViewCell {
    ...
    override func layoutSubviews() {
        super.layoutSubviews()
        let leading = contentView.directionalLayoutMargins.leading
        textLabel?.frame.origin.x = leading
    }
    ...
}

And of course you need the layout margins to be properly set for that to work

Igor Vasilev
  • 356
  • 4
  • 6
4

It appears the only solution I can find is to subclass UITableViewCell, and then override the layout of the imageView and textLabel. While researching this approach I found this related answer. (I guess I didn't realize this whole time I was searching for tableview behavior that was originally in iOS 6.)

My subclass has this one and only overridden method:

- (void)layoutSubviews
{
    [super layoutSubviews];

    // Slide image to the left, eliminating gutter
    self.imageView.frame = CGRectMake(0, 0, self.imageView.frame.size.width, self.imageView.frame.size.height);

    // Slide text label to the left, and extend width by additional
    // space gained by eliminating the left-most gutter
    self.textLabel.frame = CGRectMake((self.imageView.frame.origin.x + self.imageView.frame.size.width + 15), 0, self.textLabel.frame.size.width + 15, self.textLabel.frame.size.height);
}

My resulting tableview now looks exactly the way I want:

enter image description here

Community
  • 1
  • 1
Mason G. Zhwiti
  • 6,444
  • 11
  • 61
  • 97
2

I think I just came up with an easy solution, which I found over stackoverflow, one way to adjust cell margins, add this method in you code

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
    if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) {
        [tableView setSeparatorInset:UIEdgeInsetsZero];
    }
    if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) {
    [tableView setLayoutMargins:UIEdgeInsetsZero];
    }
    if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) {
    cell.preservesSuperviewLayoutMargins = NO;
    [cell setLayoutMargins:UIEdgeInsetsZero];
    }
    if ([cell respondsToSelector:@selector(setSeparatorInset:)]){
    [cell setSeparatorInset:UIEdgeInsetsZero];
    }
}

This solves my problem.

Swift 3 and 4

public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
        cell.separatorInset = .zero
    }
    if (cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins))) {
        cell.preservesSuperviewLayoutMargins = false
    }

    if (cell.responds(to: #selector(setter: UIView.layoutMargins))) {
        cell.layoutMargins = UIEdgeInsets.zero
    }
    if tableView.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
        tableView.separatorInset = .zero
    }

}
Chetan
  • 881
  • 14
  • 22
0

iOS 8+

In your table view:

table.separatorInset = UIEdgeInsets.zero     // or UIEdgeInsetsZero

You may also need:

table.layoutMargins = UIEdgeInsets.zero

Credit to https://stackoverflow.com/a/30640595/385273.

Ben
  • 54,723
  • 49
  • 178
  • 224
0

You can try;

[cell.textLabel setTranslatesAutoresizingMaskIntoConstraints:false];
[cell.textLabel.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor].active = YES;
[cell.textLabel.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:22].active = YES; 
eildiz
  • 487
  • 1
  • 7
  • 14