The question is what\'s the right-most way to display a separator in the last cell in a table/section.
Basically this is what I am after.
You can do something like this if you are not using sections:
- (void)viewDidLoad
{
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(insetLeftSide, 0, width - insetRightSide, 1)];
}
If you are using sections implement the footer in each section as a one point View in the methods
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
}
This will allow you to have a separator for your last cell which in fact is not a separator is a footer that you can play with it and make it look like a separator
If you add an empty footer then the tableview will remove all the remaining line separators (for non-existent cells) but will still include the separator for the last cell:
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [UIView new];
}
When you add headerView or footerView to your TableView, last separator line will disappear.
Example below will let you make workaround for showing separator on the last cell. The only thing you have to implement more is to make this separator disappearing after selecting cell, so behavior is the same like in the rest of cells.
For Swift 4.0
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let result = UIView()
// recreate insets from existing ones in the table view
let insets = tableView.separatorInset
let width = tableView.bounds.width - insets.left - insets.right
let sepFrame = CGRect(x: insets.left, y: -0.5, width: width, height: 0.5)
// create layer with separator, setting color
let sep = CALayer()
sep.frame = sepFrame
sep.backgroundColor = tableView.separatorColor?.cgColor
result.layer.addSublayer(sep)
return result
}
I just found something that works for me. In a few words: give your UITableView a tableFooterView and set its frame's height to 0. This makes an actual separator show, with the right insets.
In more details: if you are using the storyboard, drag a UIView to the bottom of your Table View (in the tree view on the left) so it shows just below Table View Cell, at the same hierarchical level. This creates a tableFooterView. Of course this can be done programmatically as well.
Then, in your UITableViewController's implementation:
UIView *footerView = self.tableView.tableFooterView;
CGRect footerFrame = footerView.frame;
footerFrame.size.height = 0;
[footerView setFrame:footerFrame];
Let me know if that works for you! It might also work for the first separator if you use a tableHeaderView instead, I haven't tried it though.
I had a similar issue and found a workaround. Apple hides the last uitableviewcell separator and then displays it if you select the cell or if you call select and deselect on that cell.
So I taught the best is in - (void)layoutSubviews
. The separator view is called _separatorView
and it's a private property. Using the cell's selected / highlighted states you can come up with something like this:
- (void)layoutSubviews
{
// Call super so the OS can do it's layout first
[super layoutSubviews];
// Get the separator view
UIView *separatorView = [self valueForKey:@"_separatorView"];
// Make the custom inset
CGRect newFrame = CGRectMake(0.0, 0.0, self.bounds.size.width, separatorView.frame.size.height);
newFrame = CGRectInset(newFrame, 15.0, 0.0);
[separatorView setFrame:newFrame];
// Show or hide the bar based on cell state
if (!self.selected) {
separatorView.hidden = NO;
}
if (self.isHighlighted) {
separatorView.hidden = YES;
}
}
Something like this.
Swift 3
I found this old issue, so I tried the same in Swift:
tableView.tableFooterView = UIView()
tableView.tableFooterView?.height = 0 // Maybe not necessary
But it lead to another problem (in my case). So I solved it differently. I added an extra cell at the end of this section, empty and with height equal to zero:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return previousNumberOfRows + 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.row == previousNumberOfRows ? 0 : previousCellHeight
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == items.count {
return UITableViewCell()
} else {
previousCellInitialization()
}
This is a less concise solution, but works in more cases, if you have multiple sections, existing footer view(s)...