How to remove the last border of the last cell in UITableView?

In my app, I use a UITableView My problem is that I want to remove the last border of the last cell in UITableView.

Please check the following image:

enter image description here

58520 次浏览

Updated on 9/14/15. My original answer become obsolete, but it is still a universal solution for all iOS versions:

You can hide tableView's standard separator line, and add your custom line at the top of each cell. The easiest way to add custom separator is to add simple UIView of 1px height:

UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.bounds.size.width, 1)];
separatorLineView.backgroundColor = [UIColor grayColor];
[cell.contentView addSubview:separatorLineView];

To date, I subscribe to another way for hiding extra separators below cells (works for iOS 6.1+):

self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];

In iOS 7 there is an easier solution. Supposing cell is your last cell:

cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0);

Here is the remedy I currently use. it might not be the best approach, but it works.

Remove SeparatorColor and setSeparatorStyle to make custom separator

- (void)viewDidLoad
{
[super viewDidLoad];


...


[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
[self.tableView setSeparatorColor:[UIColor clearColor]];
}

Add custom separator to each cell with tableview background

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];


...


UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, cell.frame.size.height-1, 320, 1)];
separatorLineView.backgroundColor = self.tableView.backgroundColor;
[cell.contentView addSubview:separatorLineView];


return cell;
}

This works for me in iOS 7 and 8:

cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, CGRectGetWidth(tableView.bounds));

NOTE: be careful about using tableView.bounds as it sometimes reports the wrong value depending on when you call it. See Reporting incorrect bounds in landscape Mode

The best solution is add a footer view. The following code hide the last cell's line perfectly:

Objective-C

self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 1)];

Swift 4.0

tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 1))

Expanding on Tonny Xu's answer, I have multiple sections and this seems to work for removing the last cells separator

if(indexPath.row == [self.tableView numberOfRowsInSection:indexPath.section] - 1)
{
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 1)];
}

In the cellForRowAtIndexPath datasource

_tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];

For iOS 7 and above

    -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
BOOL bIsLastRow = NO;


//Add logic to check last row for your data source
NSDictionary *dict = [_arrDataSource objectAtIndex:indexPath.section];
if([_arrDataSource lastObject] == dict)
{
bIsLastRow = YES;
}


//Set last row separate inset left value large, so it will go outside of view
if ([cell respondsToSelector:@selector(setSeparatorInset:)])
{
[cell setSeparatorInset:UIEdgeInsetsMake(0, bIsLastRow ? 1000 :0, 0, 0)];
}
}

My shorter version:

self.tblView.tableFooterView = [UIView new];

Find the last cell index in the cellForRow delegate and put the line of code from below:

cell.separatorInset = UIEdgeInsetsMake(
0.f,
40.0f,
0.f,
self.view.frame.size.width-40.0f
);

Another option is by subclassing UITableView:

@synthesize hideLastSeparator = _hideLastSeparator;
@synthesize hideLastSeparatorView = _hideLastSeparatorView;
-(void)setHideLastSeparator:(BOOL)hideLastSeparator {
if (_hideLastSeparator == hideLastSeparator) {
return;
}
_hideLastSeparator = hideLastSeparator;
if (_hideLastSeparator) {
_hideLastSeparatorView = [[UIView alloc] initWithFrame:CGRectMake(0, self.contentSize.height, self.bounds.size.width, 0.5f)];
_hideLastSeparatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
_hideLastSeparatorView.backgroundColor = self.backgroundColor;
[self addSubview:_hideLastSeparatorView];
[self hideSeparator];
}
else {
[_hideLastSeparatorView removeFromSuperview];
_hideLastSeparatorView = nil;
}
}
-(void)setContentSize:(CGSize)contentSize {
[super setContentSize:contentSize];
if (_hideLastSeparator) {
[self hideSeparator];
}
}
-(void)hideSeparator {
CGRect frame = _hideLastSeparatorView.frame;
frame.origin.y = self.contentSize.height - frame.size.height;
_hideLastSeparatorView.frame = frame;
}

The .h should only contain property declarations for hideLastSeparator and hideLastSeparatorView.
When wanting to hide the separator, use the new class and set myTableView.hideLastSeparator = YES.
The way this works is by obstructing the last separator by adding a new view over it.

This is somewhat easier to use in my opinion (than using a custom separator, or setting the last separatorInset of the last cell), and avoids some weird animations that the method of setting a tableFooterView sometimes causes (e.g. during row insertion/deletion or other table animations).

In Swift simply:

tableView.tableFooterView = UIView()

Below code helps me to remove the separator from last row in a UITableView.

Swift 3.0

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) {
cell.separatorInset.right = cell.bounds.size.width
}
}

Add this line of code in viewDidLoad().

tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.001))

This make sure the last separator will be replaced and replaced (invisible) footer view will not occupy any extra height. Since the footer view's width will be managed by UITableView, so you can set it to 0.

Swift 4.2

To get a separator that goes from left to right in your last cell, add this in your UITableViewDataSource's tableView(_:cellForRowAt:) implementation:

if tableView.numberOfRows(inSection: indexPath.section) - 1 == indexPath.row {
cell.separatorInset = .zero
}

If you don't want a separator for one particular cell, consider drawing your own separator and set tableView.separatorStyle = .none.

Extension based solution for Swift 4, tested on iOS 12

I noticed that setting a empty view of height = 1 also removes the separator of the last visible cell however setting height = 0 just removes the separator of the empty cells

extension UITableView {
func removeSeparatorsOfEmptyCells() {
tableFooterView = UIView(frame: .zero)
}


func removeSeparatorsOfEmptyCellsAndLastCell() {
tableFooterView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 0, height: 1)))
}
}

If you're using custom separators for your UITableViewCell the best solution is:

  1. Implement in your custom cell function, that hides separatorView
class YourCell: UITableViewCell {
// Your implementation goes here...
// Separator view in cell
@IBOutlet private weak var separatorView: UIView!


// This function hides the separator view
func hideSeparator() {
separatorView.isHidden = true
}
}
  1. In tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) calculate if the cell is the last and hides it's separator
public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? YourCell else {
return
}
// Here we're checking if your cell is the last one
if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
// if true -> then hide it
cell.hideSeparator()
}
}

Xcode 12, Swift 5

for removing separator after last cell, select grouped UITableView style You can do that in Interface Builder or setup it in viewDidLoad

tableView.style = UITableView.Style.grouped

remove empty space before first cell, write this code in viewDidLoad:

tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 0.1))

for removing empty space before your cells, and you are going to scroll it under the navigation bar or have other difficulties with avoiding empty space, try to constraint your table to controller's super view Here double click the top constraint and then choose 'SuperView.Top' at the constraint settings

If you want full width separator or your own width of it, just select Separator Inset as Custom, and configure to your values, or write it in viewDidLoad:

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

The most suitable & easy way would be using this at cellForRowAt

cell.drawBottonLine = (indexPath.row != sections[0].rows.count - 1)

This works great for me:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? yourCell else {
return
}
// Here we're checking if your cell is the last one
if indexPath.row == numberOfCells.count - 1 {
cell.separatorInset.left = UIScreen.main.bounds.width
}
}

What we're doing here is setting the size of the left inset to be a big enough value so that the separator line won't be visible anymore. So when we increase the size value of our inset it will get closer and closer to the right of our screen since left inset goes towards the right direction.

I tested and is working in Swift 5, iOS 15 and in xCode 13.3.1, Just Paste this code in TableView "cellForRowAt" method just before return cell as it pushes last line out of the frame....Note:-("arrayCartItems" will be your Array which you are returning in "numberOfRowsInSection" and "tblVw" is your Outlet name of UITableView in ViewController) Written in detail so that even Newbies could easily learn:)

    if indexPath.row == arrayCartItems.count - 1 {
cell.separatorInset = UIEdgeInsets.init(top: 0, left: tblVw.bounds.width + 1, bottom: 0, right: 0)
} else {
cell.separatorInset = .zero
}