Ios 8 Uitableview Separator Inset 0 Not Working

iOS 8 UITableView separator inset 0 not working

iOS 8.0 introduces the layoutMargins property on cells AND table views.

This property isn't available on iOS 7.0 so you need to make sure you check before assigning it!

The easy fix is to subclass your cell and override the layout margins property as suggested by @user3570727. However you will lose any system behavior like inheriting margins from the Safe Area so I do not recommend the below solution:

(ObjectiveC)

-(UIEdgeInsets)layoutMargins { 
return UIEdgeInsetsZero // override any margins inc. safe area
}

(swift 4.2):

override var layoutMargins: UIEdgeInsets { get { return .zero } set { } }

If you don't want to override the property, or need to set it conditionally, keep reading.


In addition to the layoutMargins property, Apple has added a property to your cell that will prevent it from inheriting your Table View's margin settings. When this property is set, your cells are allowed to configure their own margins independently of the table view. Think of it as an override.

This property is called preservesSuperviewLayoutMargins, and setting it to NO will allow the cell's layoutMargin setting to override whatever layoutMargin is set on your TableView. It both saves time (you don't have to modify the Table View's settings), and is more concise. Please refer to Mike Abdullah's answer for a detailed explanation.

NOTE: what follows is a clean implementation for a cell-level margin setting, as expressed in Mike Abdullah's answer. Setting your cell's preservesSuperviewLayoutMargins=NO will ensure that your Table View does not override the cell settings. If you actually want your entire table view to have consistent margins, please adjust your code accordingly.

Setup your cell margins:

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

// Prevent the cell from inheriting the Table View's margin settings
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}

// Explictly set your cell's layout margins
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}

Swift 4:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// Remove seperator inset
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = .zero
}
// Prevent the cell from inheriting the Table View's margin settings
if cell.responds(to: #selector(setter: UITableViewCell.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
// Explictly set your cell's layout margins
if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
cell.layoutMargins = .zero
}
}

Setting the preservesSuperviewLayoutMargins property on your cell to NO should prevent your table view from overriding your cell margins. In some cases, it seems to not function properly.

If all fails, you may brute-force your Table View margins:

-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];

// Force your tableview margins (this may be a bad idea)
if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[self.tableView setSeparatorInset:UIEdgeInsetsZero];
}

if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[self.tableView setLayoutMargins:UIEdgeInsetsZero];
}
}

Swift 4:

func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Force your tableview margins (this may be a bad idea)
if tableView.responds(to: #selector(setter: UITableView.separatorInset)) {
tableView.separatorInset = .zero
}
if tableView.responds(to: #selector(setter: UITableView.layoutMargins)) {
tableView.layoutMargins = .zero
}
}

...and there you go! This should work on iOS 7 and 8.


EDIT: Mohamed Saleh brought to my attention a possible change in iOS 9. You may need to set the Table View's cellLayoutMarginsFollowReadableWidth to NO if you want to customize insets or margins. Your mileage may vary, this is not documented very well.

This property only exists in iOS 9 so be sure to check before setting.

if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
myTableView.cellLayoutMarginsFollowReadableWidth = NO;
}

Swift 4:

if myTableView.responds(to: #selector(setter: self.cellLayoutMarginsFollowReadableWidth)) {
myTableView.cellLayoutMarginsFollowReadableWidth = false
}

(above code from iOS 8 UITableView separator inset 0 not working)

EDIT: Here's a pure Interface Builder approach:

TableViewAttributesInspector
TableViewCellSizeInspector

NOTE: iOS 11 changes & simplifies much of this behavior, an update will be forthcoming...

iOS 8 UITableView separator inset 0 not working

iOS 8.0 introduces the layoutMargins property on cells AND table views.

This property isn't available on iOS 7.0 so you need to make sure you check before assigning it!

The easy fix is to subclass your cell and override the layout margins property as suggested by @user3570727. However you will lose any system behavior like inheriting margins from the Safe Area so I do not recommend the below solution:

(ObjectiveC)

-(UIEdgeInsets)layoutMargins { 
return UIEdgeInsetsZero // override any margins inc. safe area
}

(swift 4.2):

override var layoutMargins: UIEdgeInsets { get { return .zero } set { } }

If you don't want to override the property, or need to set it conditionally, keep reading.


In addition to the layoutMargins property, Apple has added a property to your cell that will prevent it from inheriting your Table View's margin settings. When this property is set, your cells are allowed to configure their own margins independently of the table view. Think of it as an override.

This property is called preservesSuperviewLayoutMargins, and setting it to NO will allow the cell's layoutMargin setting to override whatever layoutMargin is set on your TableView. It both saves time (you don't have to modify the Table View's settings), and is more concise. Please refer to Mike Abdullah's answer for a detailed explanation.

NOTE: what follows is a clean implementation for a cell-level margin setting, as expressed in Mike Abdullah's answer. Setting your cell's preservesSuperviewLayoutMargins=NO will ensure that your Table View does not override the cell settings. If you actually want your entire table view to have consistent margins, please adjust your code accordingly.

Setup your cell margins:

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

// Prevent the cell from inheriting the Table View's margin settings
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}

// Explictly set your cell's layout margins
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}

Swift 4:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// Remove seperator inset
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = .zero
}
// Prevent the cell from inheriting the Table View's margin settings
if cell.responds(to: #selector(setter: UITableViewCell.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
// Explictly set your cell's layout margins
if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
cell.layoutMargins = .zero
}
}

Setting the preservesSuperviewLayoutMargins property on your cell to NO should prevent your table view from overriding your cell margins. In some cases, it seems to not function properly.

If all fails, you may brute-force your Table View margins:

-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];

// Force your tableview margins (this may be a bad idea)
if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[self.tableView setSeparatorInset:UIEdgeInsetsZero];
}

if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[self.tableView setLayoutMargins:UIEdgeInsetsZero];
}
}

Swift 4:

func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Force your tableview margins (this may be a bad idea)
if tableView.responds(to: #selector(setter: UITableView.separatorInset)) {
tableView.separatorInset = .zero
}
if tableView.responds(to: #selector(setter: UITableView.layoutMargins)) {
tableView.layoutMargins = .zero
}
}

...and there you go! This should work on iOS 7 and 8.


EDIT: Mohamed Saleh brought to my attention a possible change in iOS 9. You may need to set the Table View's cellLayoutMarginsFollowReadableWidth to NO if you want to customize insets or margins. Your mileage may vary, this is not documented very well.

This property only exists in iOS 9 so be sure to check before setting.

if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
myTableView.cellLayoutMarginsFollowReadableWidth = NO;
}

Swift 4:

if myTableView.responds(to: #selector(setter: self.cellLayoutMarginsFollowReadableWidth)) {
myTableView.cellLayoutMarginsFollowReadableWidth = false
}

(above code from iOS 8 UITableView separator inset 0 not working)

EDIT: Here's a pure Interface Builder approach:

TableViewAttributesInspector
TableViewCellSizeInspector

NOTE: iOS 11 changes & simplifies much of this behavior, an update will be forthcoming...

How do I make the UITableView separator inset go from the edges of the screen?

Since launch of iOS 8.0, apple added layoutMargins property for UITableViewCell and UITableView.

So you can set layoutMargin to zero in willDisplayCell: delegate method of TableView. This code just set tableview layoutMargin and cell layoutMargin as UIEdgeInsetsZero .

This will work for iOS 7.0 also.

Try this may help you.

Swift

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

if(tableView.respondsToSelector("setSeparatorInset:")){

tableView.separatorInset = UIEdgeInsetsZero
}

if(tableView.respondsToSelector("setLayoutMargins:")){

tableView.layoutMargins = UIEdgeInsetsZero
}

if(cell.respondsToSelector("setLayoutMargins:")){

cell.layoutMargins = UIEdgeInsetsZero
}

}

Objective C

-(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 ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}

For iOS 9.0, you have to set cellLayoutMarginsFollowReadableWidth to NO.

Objective C

- (void)viewDidLoad {
[super viewDidLoad];

//For iOS 9 and Above

if ([[[UIDevice currentDevice]systemVersion]floatValue] >= 9.0) {
self.tableView.cellLayoutMarginsFollowReadableWidth = NO;
}
}

Swift

override func viewDidLoad() {
super.viewDidLoad()

//For iOS 9 and Above
if #available(iOS 9, *) {
tableView.cellLayoutMarginsFollowReadableWidth = false
}
}

You can also set this value from Storyboard.

Open Storyboard and go to Attribute Inspector for TableView Cell.

Change type of Separator field to Custom Insets and change value of Left to 0.

Please find below image.

Sample Image

iOS 9 UITableView separators insets (significant left margin)

Okay, I have found out the solution. The only thing required for that is to set on the presenting instance of UITableView that flag cellLayoutMarginsFollowReadableWidth

myTableView.cellLayoutMarginsFollowReadableWidth = NO;

I wanted to find some reference in the documentation but it looks like it is not ready yet, only mentioned on diff page.

As the flag was introduced in iOS 9 for the backward compatibility you should add a check before trying to set it:

if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
myTableView.cellLayoutMarginsFollowReadableWidth = NO;
}

For Swift 2.0 you can use #available to check iOS version.

if #available(iOS 9, *) {
myTableView.cellLayoutMarginsFollowReadableWidth = false
}

Moreover you need to compile it with Xcode 7 or above.

EDIT

Please keep in mind that this is the only required fix if your separators looked "fine" up to iOS 8, otherwise you need to change a bit more. You can find info how to do this already on SO.

Remove SeparatorInset on iOS 8 UITableView for Xcode 6 iPhone Simulator

Thanks Student for pointing me to the right direction with the comment "Try this self.myTableView.layoutMargins = UIEdgeInsetsZero;" This line of code will only work on iOS 8 because layoutMargins is only available from iOS 8. If I run the same code on iOS 7, it will crash.

@property(nonatomic) UIEdgeInsets layoutMargins
Description The default spacing to use when laying out content in the view.
Availability iOS (8.0 and later)
Declared In UIView.h
Reference UIView Class Reference

Sample Image

Below is the right answer to solve this weird white space by setting the tableview layoutMargins and cell layoutMargins as UIEdgeInsetsZero if it exists (for iOS 8). And it will not crash on iOS 7 as well.

-(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 ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}

See the screen shot below:-

Sample Image

Separator insets not working

You have to subclass UITableViewCell and call layoutSubviews from your newly created UITableViewCell class, in the layoutSubviews method, use

- (void)layoutSubviews{
[super layoutSubviews];
self.imageView.frame = CGRectMake(0, 0, 50, 50); // override frame of your choice
}


Related Topics



Leave a reply



Submit