164

I have a UITableView where the separators don't have the full width. It ends like 10 pixels before the left side. I was playing around with this code in the viewDidLoad().

self.tableView.layoutMargins = UIEdgeInsetsZero;

Also in the storyboard when you can select custom or default selectors. Now all the cells that are populated don't have the full-width selectors but the cells that are empty have full width.

How can I fix this?

Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
Timo Cengiz
  • 3,367
  • 4
  • 23
  • 45
  • 10
    `UITableView` has a property `separatorInset`. Set the inset of the `UITableView`line separator to zero. Also you can change the `separatorInset` from the storyboard – Moonhead Oct 23 '14 at 00:14

16 Answers16

238

This worked for me on iOS 8.4 - 9.0 devices using Xcode 6.4 and Swift 1.2:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = UITableViewCell()


    cell.preservesSuperviewLayoutMargins = false
    cell.separatorInset = UIEdgeInsetsZero
    cell.layoutMargins = UIEdgeInsetsZero

    return cell
}

Swift 5 Update:

cell.preservesSuperviewLayoutMargins = false
cell.separatorInset = UIEdgeInsets.zero
cell.layoutMargins = UIEdgeInsets.zero
SwiftiSwift
  • 7,528
  • 9
  • 56
  • 96
MB_iOSDeveloper
  • 4,178
  • 4
  • 24
  • 36
  • Why does this remove my table with a blank one? The seperators are moved but I cant see any of my buttons – Oscar Mar 10 '16 at 13:55
  • 1
    @James could you please explain " remove my table with a blank one?". How have you added your buttons (via IB, code)? – MB_iOSDeveloper Mar 11 '16 at 07:13
  • 1
    Very nice solution. But in my case I put code straight to the cell initialization, beacuse I wanted to have full width of separator in all controllers. – Vojta May 08 '16 at 17:13
  • In case it isn't obvious, this also works for Objective-C with the proper syntax changes of course. – cohenadair Aug 19 '16 at 19:35
  • cell.layoutMargins = UIEdgeInsets.zero is enough if you have insets = 0 for tableview separators in storyboard/xib. preservesSuperviewLayoutMargins is false by default. – Maria Dec 13 '16 at 08:37
  • 1
    None of these solutions work on an iPad. This only works on an iPhone... – Charles Robertson Dec 19 '16 at 13:34
  • @Hannah Louisa Carney answer is better. This leaves default insets for empty rows. – Makalele Jul 27 '17 at 11:20
108

In your UITableViewCell

Go to Attributes Inspector in your Interface Builder and simply change "15" to 0. Do this for all the cells you wish to change.

instets

You may need to add [cell setLayoutMargins:UIEdgeInsetsZero]; to your tableViewCell

Kuldeep
  • 4,466
  • 8
  • 32
  • 59
HannahCarney
  • 3,441
  • 2
  • 26
  • 32
  • 1
    Or that's weird. This did work for me (thank you !) on the rows where I had UITableViewCells to be displayed, but on any empty rows below them, the separator was still indented by 15 pixels. – Mike Gledhill Dec 19 '16 at 13:19
  • If you are using static cells, all you need is to change the left inset to 0 like described in the image (Working in iOS 10, Xcode 8.3.1) – Ignacio Valdivieso Apr 15 '17 at 03:28
103

I got the answer from this post: iOS 8 UITableView separator inset 0 not working

Just add this code on your UITableViewController

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

    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
}

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
        [self.tableView setSeparatorInset:UIEdgeInsetsZero];
    }

    if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
        [self.tableView setLayoutMargins:UIEdgeInsetsZero];
    }
}
Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
Timo Cengiz
  • 3,367
  • 4
  • 23
  • 45
  • 2
    it works for me for adding only the tableView delegate method – TonyTony Jan 23 '15 at 08:57
  • Im sorry i did not understad. You mean that it was enough for you to add the TableViewDeleagte?. I just tried just adding that it did not work for me @TonyTony – Timo Cengiz Jan 23 '15 at 10:01
  • 3
    for me the method `viewDidLayoutSubviews` is not necessary – TonyTony Jan 24 '15 at 11:54
  • DId you try to run your code with other IOS versions than 8? Maybe it works for the newest ones. Otherwise good for you that it works. I tried just adding the tableview delegate method and it did not help. @TonyTony – Timo Cengiz Jan 24 '15 at 12:03
  • I had to use both. I tried using each individually with no success. It only worked when I used both. In addition, I tried it when my view controller was a subclass of UITableViewController, and when it was a subclass of UIViewController. No difference. Note that I'm running in the 8.1 simulator. – Ron Feb 08 '15 at 04:34
  • it pains me to have to say this, but the iOS SDK is slowly becoming a disaster. Why would adjusting the separator insert be so tedious. Gosh. – pnizzle Aug 26 '15 at 07:35
  • Note that this won't adjust the separators on 'placeholder' cells displayed by the controller to fill up the view below your cells if you cells don't make up the full height. – Tieme Oct 30 '15 at 09:17
  • For future users: on iOS 9 you need both. – Wyetro Jul 20 '16 at 20:57
  • @WMios are you sure? I just tried iOS 9.3 (13E230) and implementation of `viewDidLoad` is not needed (willDisplayCell works alone). – JakubKnejzlik Aug 21 '16 at 08:33
  • It's `viewDidLayoutSubviews` which differs from `viewDidLoad` and in the end I did not need it. – Wyetro Aug 21 '16 at 17:29
30

for Swift 3 :

override func viewDidLoad() {
  super.viewDidLoad()

  tableView.separatorInset = .zero
  tableView.layoutMargins = .zero
}
Wilson
  • 9,006
  • 3
  • 42
  • 46
25
  1. Select your UITableViewCell
  2. Go to Atributes Inspector
  3. Go to Separator and change it to "custom Insets"
  4. Set left and / or right fields. (By default left: 15, right: 0)

Look how it works (using left: 100):

enter image description here

Result:

enter image description here

Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
Sebastián Lara
  • 5,355
  • 2
  • 28
  • 21
19

I inherit from UITableViewController and needed additional to the two insets settings in willDisplayCell also to set preservesSuperviewLayoutMargins to false. In Swift it looks like this:

override func tableView(_tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

    if cell.respondsToSelector("setSeparatorInset:") {
        cell.separatorInset = UIEdgeInsetsZero
    }
    if cell.respondsToSelector("setLayoutMargins:") {
        cell.layoutMargins = UIEdgeInsetsZero
    }
    if cell.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
        cell.preservesSuperviewLayoutMargins = false
    }
}
Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
disco crazy
  • 31,313
  • 12
  • 80
  • 83
  • You don't need to set `preservesSuperviewLayoutMargins = false` because default value is already false – crubio Oct 13 '15 at 17:14
  • 2
    Note that this won't adjust the separators on 'placeholder' cells displayed by the controller to fill up the view below your cells if you cells don't make up the full height. – Tieme Oct 30 '15 at 09:17
12

The Separator Inset is by default 15 from left. Change Separator Inset option from auto to custom and set the inset to 0.

enter image description here

Ali
  • 2,702
  • 3
  • 32
  • 54
Ramin
  • 335
  • 4
  • 14
9

For Swift in iOS 9+

If using a custom UITableViewCell:

override var layoutMargins: UIEdgeInsets {
    get { return UIEdgeInsetsZero }
    set(newVal) {}
}

then for your UITableView in viewDidLoad:

self.tableView?.separatorInset = UIEdgeInsetsZero;
self.tableView?.layoutMargins = UIEdgeInsetsZero;
Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
Christopher Larsen
  • 1,375
  • 15
  • 22
  • This is the only answer that fixed it for me (updated to swift 3). However... it works when there is data in the cell. For blank cells that have not yet been filled (and I guess haven't called this overriden layoutMargins variable) the separator still does not fill the full width of my custom cell in the tableview. Any ideas on that? – RanLearns May 13 '17 at 01:32
  • On the iPhone, the separator ends just a few pixels from the left and a few pixels from the right on empty cells. That looks alright without using this trick to zero out the margins. On the iPad is the real problem - the separators on an empty cell go from the left edge of the tableview, only about 80% of the width of the cell. When there is data in the cell, the separator is still 80% of the cell width, but it starts 20% of the way in and goes all the way to the right edge of the tableview – RanLearns May 13 '17 at 01:42
  • 1
    Figured out a solution... using if #available(iOS 9, *) { self.tableView.cellLayoutMarginsFollowReadableWidth = false } made it so I don't need your code at all on iPhone. The separator just goes the full width. On iPad, the empty cells have a full width separator, but I need your code in order to keep full width when data is added. Otherwise, there are a few pixels to the left added where there is no separator once data fills the cell. – RanLearns May 13 '17 at 01:51
  • 1
    Answer where I got the code in the comment above from: https://stackoverflow.com/a/31538250/428981 – RanLearns May 24 '17 at 19:13
9

Use it in cellForRowAtIndexPath method, to configure cell's separator specs ,
it works perfect for iOS9.0+

 cell.separatorInset = UIEdgeInsetsZero;
 cell.layoutMargins = UIEdgeInsetsZero;
 cell.preservesSuperviewLayoutMargins = NO;
Ash
  • 5,525
  • 1
  • 40
  • 34
9

For people having issues with the iPad — this will get you in a state that is the same as the iPhone. You can then adjust the separatorInset as needed.

tableView.cellLayoutMarginsFollowReadableWidth = false
Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
rosem
  • 1,311
  • 14
  • 19
  • This was my problem on iOS 10 vs iOS 11. iOS 11 was fine, but 10 had different margins. Thanks!!! – migs647 Apr 17 '18 at 23:38
8

Tested for iOS 9.3 & Swift 2.2. Make sure to put the code in willDisplayCell which is called just before displaying the cell and not in cellForRowAtIndexPath where you create the cell only.

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    cell.separatorInset = UIEdgeInsetsZero
    cell.layoutMargins = UIEdgeInsetsZero
}

Add override to the function for UITableViewController, like so:

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
oyalhi
  • 3,834
  • 4
  • 40
  • 45
8

swift 5, Xcode 11 Update

place this inside viewDidLoad()

yourTableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

for edge to edge separator just set the value of left and right to 0.

by the way change the "yourTableView" to your tableView Outlet name.

Developersian
  • 151
  • 2
  • 7
5

None of the above worked for me in Swift 2.2 and Xcode 7.3.1

Turned out to be the simplest solution of all. No code needed. Just change TableViewCell Layout Margins values in your UITableView inspector:

Kuldeep
  • 4,466
  • 8
  • 32
  • 59
aurawindsurfing
  • 423
  • 4
  • 11
4

For Swift 3 :

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
        cell.separatorInset = UIEdgeInsets.zero
    }
    if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
        cell.layoutMargins = UIEdgeInsets.zero
    }
    if cell.responds(to: #selector(setter: UITableViewCell.preservesSuperviewLayoutMargins)) {
        cell.preservesSuperviewLayoutMargins = false
    }
}
Nilanshu Jaiswal
  • 1,583
  • 3
  • 23
  • 34
Giulio Colleluori
  • 1,261
  • 2
  • 10
  • 16
1

In viewDidLoad (tested iOS11 - swift 4.1)

try

tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)

Giang
  • 2,384
  • 2
  • 25
  • 26
0

None of these solutions work on the iPad, but I have come up with a solution that covers both devices:

With reusable cells:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    ...[other code]...
    [cell setLayoutMargins:UIEdgeInsetsZero];
    [cell setSeparatorInset:UIEdgeInsetsZero];
    return cell;
}

With non reusable cells:

- (void)removeSeparatorInset:(UITableView*)tableView{
    NSArray *cells = [tableView visibleCells];
    for (UITableViewCell *cell in cells){
        [cell setLayoutMargins:UIEdgeInsetsZero];
        [cell setSeparatorInset:UIEdgeInsetsZero];
    }
}

-(void) viewDidLayoutSubviews{
   [super viewDidLayoutSubviews];
   [self removeSeparatorInset:self.tableView];
}

Just to expand on this approach:

@property(nonatomic) UIEdgeInsets separatorInset;
@property(nonatomic) UIEdgeInsets layoutMargins;

Both properties can be used by UITableView & UITableViewCell. The latter is, in fact, a property of UIView, which is a parent class of both UITableView & UITableViewCell.

Kuldeep
  • 4,466
  • 8
  • 32
  • 59
Charles Robertson
  • 1,760
  • 16
  • 21