UITableViewCell Separator disappearing in iOS7

48,880

Solution 1

I dumped the subview hierarchy of affected cells and found that the _UITableViewCellSeparatorView was set to hidden. No wonder it's not shown!

I overrode layoutSubviews in my UITableViewCell subclass and now the separators are displayed reliably:

Objective-C:

- (void)layoutSubviews {
    [super layoutSubviews];

    for (UIView *subview in self.contentView.superview.subviews) {
        if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) {
            subview.hidden = NO;
        }
    }
}

Swift:

override func layoutSubviews() {
    super.layoutSubviews()

    guard let superview = contentView.superview else {
        return
    }
    for subview in superview.subviews {
        if String(subview.dynamicType).hasSuffix("SeparatorView") {
            subview.hidden = false
        }
    }
}

The other solutions proposed here didn't work consistently for me or seem clunky (adding custom 1 px footer views).

Solution 2

This worked for me:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    // fix for separators bug in iOS 7
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

Solution 3

I also had the problem with missing separator and I found out that the problem only occured when heightForRowAtIndexPath was returning a decimal number. Solution:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return ceil(yourHeight) // Ceiling this value fixes disappearing separators
}

Solution 4

Did you try adding a UIView of height 1 in the header and the footer of the table with light gray background color? Basically it'll mock the first and last separators.

Solution 5

We encountered this issue in our app. When the user selected a cell, a new table view was pushed onto the navigation controller stack and then when the user popped it off, the separator was missing. We solved it by putting [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; in the didSelectRowAtIndexPath table view delegate method.

Share:
48,880
B.S.
Author by

B.S.

Updated on September 27, 2020

Comments

  • B.S.
    B.S. over 3 years

    I have some strange issue with UITableView only in iOS 7.

    UITableViewCellSeparator disappears above the first row and below the last row. Sometimes after selecting the rows or some scrolling actions it appears.

    In my case tableView is loaded from the Storyboard with UITableViewStylePlain style. The problem is surely not in UITableViewCellSeparatorStyle, which is not changed from default UITableViewCellSeparatorStyleSingleLine.

    As I read at Apple Dev Forums (here and here) other people have such problem and some workarounds are found, for example:

    Workaround: disable the default selection and recreate the behaviour in a method
    trigged by a tapGestureRecognizer.
    

    But I am still searching for the reason of such separator strange behaviour.

    Any ideas?

    Update: As I saw in XCode 5.1 DP and iOS 7.1 beta, Apple tried to fix this problem. Now separator is shown as needed sometimes below the last row, after some refreshing, but not after tableview creation.

  • B.S.
    B.S. over 10 years
    What about the case if I do not implement even heightForRowAtIndexPath method?
  • Joney Spark
    Joney Spark over 10 years
    Interesting. However, it happens in my project as well - and heightForRowAtIndexPath isn't implemented. In IB row/cell height is 100.
  • Joney Spark
    Joney Spark over 10 years
    This workaround fixed it for me; however, I reversed it - to retain the selection. So, first deselect, then re-select.
  • Gergely Kovacs
    Gergely Kovacs over 10 years
    It did not solve the issue for me and I do have the heightForRowAtIndexPath method.
  • Nick Frolov
    Nick Frolov over 10 years
    Solves the issue at least partially. The cell does seem to be confused about non-integer heights.
  • airpaulg
    airpaulg over 10 years
    I don't know what to override when you say "after the data is reloaded"
  • wrightak
    wrightak over 10 years
    Have you tried self.tableView.allowsMultipleSelection = NO;?
  • skinsfan00atg
    skinsfan00atg over 10 years
    this sounds good, but how exactly do you do this? use viewforfooter?
  • skinsfan00atg
    skinsfan00atg over 10 years
    isn't as easy as it sounds, for some reason i had to also implement heightforfooter otherwise the height specified in the initwithframe was ignored. i also notice though that the lightgraycolor is not the same color so this won't really work. might have to make a custom gray
  • trss
    trss about 10 years
    You need to ceil the number of pixels and then divide by screen scale factor to get points which is okay to be in decimal. If you don't do this, it won't be retina optimized.
  • NiñoScript
    NiñoScript about 10 years
    You deserve more up votes, this is exactly what I needed, I added it in a category, so now after I do [tableView reloadData], if this bug happens (in my case the footer separator that was hidden is reappearing), I call [tableView reloadSeparators];
  • surfrider
    surfrider almost 10 years
    Worked for me. Thanks. Any other methods didn't help me (include separator style change from samvermette's answer).
  • agarcian
    agarcian almost 10 years
    This fix the issue for me. Thank you so much!
  • Vitalii Boiarskyi
    Vitalii Boiarskyi almost 10 years
    I have used your method but not in subclass I had added a category to UITableViewCell. It helped me. Thanks.
  • Ortwin Gentz
    Ortwin Gentz almost 10 years
    Of course it's also possible in a category. Since this requires method swizzling, I went for the simple subclass approach.
  • juhan_h
    juhan_h almost 10 years
    This is the only solution that worked for me. My problem popped up whe the UITableView had enough rows to be scrollable. That "hasSuffix:" part is quite fragile though.
  • JackyJohnson
    JackyJohnson almost 10 years
    that's pretty janky IMO
  • airpaulg
    airpaulg almost 10 years
    Yeah I fully agree. It's the sole workaround I found right after iOS 7's release, is there any better approach now?
  • Jeff
    Jeff over 9 years
    To match the color, use tableView.separatorColor
  • Foriger
    Foriger about 9 years
    Works for me. Maybe question is silly, but isn't this using of Private API ?
  • Ortwin Gentz
    Ortwin Gentz about 9 years
    Technically it's not using private API and your app won't be rejected because of this. It relies on an implementation detail though and could break in a future iOS version.
  • David
    David about 9 years
    @Foriger if you worry of using hasSuffix:@"SeparatorView", try to replace it with if(CGRectGetHeight(subview.frame) < 1.1). It probably even would work faster whether you don't use any other 1px custom views in your cell. I chose 1.1px 'cos in Retina UITableViewSeparator has 0.5 points height, but for non-Retina it could be 1.0.
  • Alex Sfinx87
    Alex Sfinx87 almost 9 years
    Works for me, grouped UITableView (iOS 7 and iOS8).
  • ObjectiveTC
    ObjectiveTC almost 9 years
    YES. This worked for me, after converting over to latest version of Swift. ++ for calling fixSeparators after every call to tableView.endUpdates().
  • Lukas Petr
    Lukas Petr almost 9 years
    I am glad this was helpful to you! I really believe this is the best solution, so hopefully more people will discover it.
  • Dan Dyer
    Dan Dyer over 8 years
    Although this mostly fixed the problem for me, for some reason one of my separators was still disappearing. Combining this fix with the toggling of tableView.separatorStyle suggested in other answers (which by itself made no difference for me) made it work for all of the separators.
  • Brett
    Brett about 8 years
    Setting clipSubviews to false in the storyboard for both the cell and the contentView fixed the issue! Needs more up votes!
  • Rene Juuse
    Rene Juuse about 7 years
    Setting clipsToBounds to YES on the cells was enough for me.