UITableView: the proper way to display a separator for the last cell

时光怂恿深爱的人放手 提交于 2019-12-20 11:05:14

问题


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.

This is from the native music app, which makes me think that it should be possible to achieve just by means of UITableView, they would not be using some private API for cell separators, right?

I know you can get away without using actual separators, but adding one pixel line in the bottom of the cell. But I'm not a fan of this approach because

  1. When a cell is selected/highlighted its separator and the separator of the previous cell are automatically hidden (see the second screenshot with "You've got to be crazy" selected). And this is something I want UITableView to handle instead of doing myself if I use one-pixel line (which is especially handy when cell separators do not extend all the way to the edge of the table view, separators and selected cell background do not look nice together).
  2. I would like to keep my cells as flat as possible for scrolling performance.

Also there is something in UITableView reference that makes me think that there is an easy way to get what I want:

In iOS 7 and later, cell separators do not extend all the way to the edge of the table view. This property sets the default inset for all cells in the table, much like rowHeight sets the default height for cells. It is also used for managing the “extra” separators drawn at the bottom of plain style tables.

Does somebody know how exactly to use these “extra” separators drawn at the bottom of plain style tables? Because this is exactly what I need. I thought assigning separatorInsetto the UITableView, not UITableViewCell would do the trick, but it does not, the last cell is still missing its separator.

Right now I only see one option: to have a custom section footer to mimic the separator for the last cell. And this is not good, especially if you want to have an actual section footer using tableView:titleForFooterInSection: method.


回答1:


This worked flawlessly for me to add a separator to the last cell. have fun!

self.tableView.tableFooterView = [[UIView alloc] init];



回答2:


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

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
}



回答3:


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.




回答4:


this will do exactly what you want .. even though the line will take the entire width of the cell:

in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.tableView.separatorColor = [UIColor redColor];
self.tableView.separatorInset = UIEdgeInsetsZero;



回答5:


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




回答6:


So here's a super simple solution in Swift 4 which works:

Inside override func viewDidLoad(){}, I simply implemented this line of code:

    self.tableView.tableFooterView = UIView(frame: .zero)

Hence it ensures that only the last cell gets the separator inset.

This worked perfectly for me, hope it does for you too!




回答7:


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.




回答8:


In iOS 8, if you have a plain style UITableView, and add a footer, the last separator is gone. However, you can easily recreate it by adding a custom separator view to the footer.

This example exactly mimics Today Widget separator style

    override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {

        //create footer view
        let result = UIView()
        result.frame.size.height = tableView.rowHeight

        //recreate last cell separator, which gets hidden by footer
        let sepFrame = CGRectMake(15, -0.5, tableView.frame.width, 0.5);
        let vibrancyEffectView = UIVisualEffectView.init(effect: UIVibrancyEffect.notificationCenterVibrancyEffect())
        vibrancyEffectView.frame = sepFrame
        vibrancyEffectView.contentView.backgroundColor = tableView.separatorColor
        result.addSubview(vibrancyEffectView)
        return result
}



回答9:


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)...




回答10:


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]; 
}



回答11:


Works in iOS 7.x and 8.x (put it in cellForRowAtIndexPath):

(PS substitute "max elements of your datasource" with your array datasource count)

 if (row == <max elements of your datasource>-1) {
     UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, cell.contentView.frame.size.height-1, self.view.frame.size.width, 1)];/// change size as you need.
     separatorLineView.tag = 666;
     separatorLineView.backgroundColor = [UIColor colorWithRed: 204.0/255.0 green: 204.0/255.0 blue: 204.0/255.0 alpha:1.0];
     UIView *separator = [cell.contentView viewWithTag:666];
     // case of orientation changed..
     if (separator.frame.size.width != cell.contentView.frame.size.width) {
        [[cell.contentView viewWithTag:666] removeFromSuperview];
        separator = nil;
     }
     if (separator==nil) [cell.contentView addSubview:separatorLineView];
 }



回答12:


This is definitely help. Working. but set separator "none" from attribute inspector. Write following code in cellForRowAtIndexPath method

if(indexPath.row==arrData.count-1){
 UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,           
 cell.contentView.frame.size.height - 1.0,      
 cell.contentView.frame.size.width, 1)];

    lineView.backgroundColor = [UIColor blackColor];
    [cell.contentView addSubview:lineView];
}



回答13:


The code below worked for me:

UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 0.35)];
footerView.backgroundColor = [UIColor whiteColor];
CGRect frame = footerView.frame;
frame.origin.x = 15;
frame.size.width = frame.size.width - 15;
UIView *blackView = [[UIView alloc] initWithFrame:frame];
[blackView setBackgroundColor:[UIColor blackColor]];
blackView.alpha = 0.25;
[footerView addSubview:blackView];
tableView.tableFooterView = footerView;

Hope it works for you too.



来源:https://stackoverflow.com/questions/19767543/uitableview-the-proper-way-to-display-a-separator-for-the-last-cell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!