UITableViewCell Separator исчезает в iOS7

У меня есть странная проблема с UITableView только в iOS 7.

UITableViewCellSeparator исчезает выше первой строки и ниже последней строки. Иногда после выбора строк или некоторых действий прокрутки появляется.

В моем случае tableView загружается из стиля Storyboard с UITableViewStylePlain. Проблема, конечно, не в UITableViewCellSeparatorStyle, которая не изменяется по умолчанию UITableViewCellSeparatorStyleSingleLine.

Как я читал в Форумы Apple Dev (здесь и здесь) у других людей есть такая проблема, и некоторые методы обхода найдены, например:

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

Но я все еще искал причину такого странного поведения разделителя.

Любые идеи?

Обновление: Как я увидел в XCode 5.1 DP и iOS 7.1 бета-версии, Apple попыталась исправить эту проблему. Теперь разделитель отображается по мере необходимости иногда ниже последней строки после некоторого обновления, но не после создания таблицы.

Ответ 1

Я сбросил иерархию подчиненных уязвимых ячеек и обнаружил, что параметр _UITableViewCellSeparatorView был скрыт. Неудивительно, что это не показано!

Я перепробовал layoutSubviews в моем подклассе UITableViewCell, и теперь разделители отображаются надежно:

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

Другие предлагаемые здесь решения не работали последовательно для меня или кажутся неуклюжими (добавление пользовательских представлений нижнего колонтитула 1 px).

Ответ 2

Это сработало для меня:

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

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

Ответ 3

У меня также возникла проблема с отсутствующим разделителем, и я узнал, что проблема возникла только тогда, когда heightForRowAtIndexPath был , возвращая десятичное число. Решение:

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

Ответ 4

Вы пытались добавить UIView высоты 1 в заголовок и нижний колонтитул таблицы со светло-серым цветом фона? В основном это будет издеваться над первым и последним разделителями.

Ответ 5

@samvermette

Я исправил проблему, используя эти методы делегата. Теперь он не мерцает:

-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
    // fix for separators bug in iOS 7
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
}


-(void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath {
    // fix for separators bug in iOS 7
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
}

Ответ 6

Мы столкнулись с этой проблемой в нашем приложении. Когда пользователь выбрал ячейку, новое табличное представление было перенесено в стек контроллера навигатора, а затем, когда пользователь выскочил, разделитель отсутствовал. Мы решили это, положив [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; в метод делегата таблицы didSelectRowAtIndexPath.

Ответ 7

Ниже приведено более легкое (хотя и немного беспорядочное) решение, если вам это нужно, попробуйте выбрать и отменить выбор ячейки после перезагрузки данных и сделать анимацию по умолчанию.

просто добавьте:

[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];

Ответ 8

Я обнаружил, что самое легкое решение - после перезагрузки ячейки также перезагрузить ячейку выше:

if (indexPath.row > 0) {
    NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section];
    [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationNone];
}

Ответ 9

Простое и чистое решение, которое работает как на iOS 8, так и на iOS 9 (бета 1)

Вот простой, чистый и неинтрузивный обходной путь. Он включает вызов метода категории, который будет фиксировать разделители.

Все, что вам нужно сделать, - это спуститься по иерархии ячейки и скрыть разделитель. Вот так:

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

Я рекомендую добавить это в категорию в UITableViewCell, например:

@interface UITableViewCell (fixSeparator)
- (void)fixSeparator;
@end

@implementation UITableViewCell (fixSeparator)

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

@end

Поскольку разделитель может исчезнуть в другой ячейке, чем выбранная в данный момент, вероятно, рекомендуется называть это исправление для всех ячеек в представлении таблицы. Для этого вы можете добавить категорию в UITableView, которая будет выглядеть следующим образом:

@implementation UITableView (fixSeparators)

- (void)fixSeparators {
    for (UITableViewCell *cell in self.visibleCells) {
        [cell fixSeparator];
    }
}

@end

С помощью этого места вы можете вызвать -fixSeparatos в таблицеView сразу после действия, которое приведет к их исчезновению. В моем случае это было после вызова [tableView beginUpdates] и [tableView endUpdates].

Как я уже говорил в начале, я тестировал это как на iOS 8, так и на iOS 9. Я полагаю, что он будет работать даже на iOS 7, но у меня нет возможности попробовать его. Как вы, вероятно, знаете, это водится с внутренними элементами ячейки, поэтому он может перестать работать в какой-то будущей версии. И Apple теоретически (вероятность 0.001%) отклоняет ваше приложение из-за этого, но я не вижу, как они могут даже узнать, что вы там делаете (проверка суффикса класса не может быть обнаружена статическими анализаторами как нечто плохо, ИМО).

Ответ 10

Основываясь на комментарии @ortwin-gentz, это решение работает для меня в iOS 9.

func fixCellsSeparator() {

    // Loop through every cell in the tableview
    for cell: UITableViewCell in self.tableView.visibleCells {

        // Loop through every subview in the cell which its class is kind of SeparatorView
        for subview: UIView in (cell.contentView.superview?.subviews)!
            where NSStringFromClass(subview.classForCoder).hasSuffix("SeparatorView") {
                subview.hidden = false
        }
    }

}

(код Swift)

Я использую функцию fixCellsSeparator() после вызова endUpdates() в некоторых методах моего tableView, например:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    //  Perform some stuff
    //  ...

    self.tableView.endUpdates()
    self.fixCellsSeparator()

}

Я надеюсь, что это решение будет полезно для кого-то!

Ответ 11

Дополнение к ответу airpaulg.

Таким образом, в основном нужно реализовать два метода UITableDelegate. Здесь мое решение работает как на iOS7, так и на iOS6.

#define IS_OS_VERSION_7 (NSFoundationVersionNumber_iOS_6_1 < floor(NSFoundationVersionNumber))

#define UIColorFromRGB(hexRGBValue) [UIColor colorWithRed:((float)((hexRGBValue & 0xFF0000) >> 16))/255.0 green:((float)((hexRGBValue & 0xFF00) >> 8))/255.0 blue:((float)(hexRGBValue & 0xFF))/255.0 alpha:1.0]

//Это скроет пустую сетку таблицы под ячейками, если они не покрывают весь экран

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    UIView *view = nil;

    if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */)
    {
        CGFloat height = 1 / [UIScreen mainScreen].scale;
        view = [[UIView alloc] initWithFrame:CGRectMake(0., 0., 320., height)];
        view.backgroundColor = UIColorFromRGB(0xC8C7CC);
        view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    }
    else
    {
        view = [UIView new];
    }
    return view;
}


- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */)
    {
        return 1 / [UIScreen mainScreen].scale;
    }
    else
    {
        // This will hide the empty table grid below the cells if they do not cover the entire screen
        return 0.01f;
    }
}

Ответ 12

Это исправило проблему для меня:

Удостоверьтесь, что для установлено значение clipsToBounds YES, но NO для ячейки contentView. Также установите cell.contentView.backgroundColor = [UIColor clearColor];

Ответ 13

Похоже, этот вопрос проявляется при столь многих обстоятельствах.

Для меня это как-то связано с выбором ячейки. Я понятия не имею, почему и не успел вникнуть в нее слишком глубоко, но могу сказать, что это началось, когда я установил ячейку selectionStyle none. то есть:

//This line brought up the issue for me
cell.selectionStyle = UITableViewCellSelectionStyleNone;

Я попытался использовать некоторые из методов делегата выше, которые включали и выключали свойство separatorStyle для tableView, но они, похоже, ничего не сделали, чтобы исправить мою проблему.

Вся причина, по которой я нуждался в этом, заключалась в том, что мне даже не нужен выбор ячейки.

Итак, я нашел что-то, что сработало для меня. Я просто отключил выделение на UITableView:

tableView.allowsSelection = NO;

Надеюсь, это поможет кому-то, если вам не нужно выбирать ячейки.

Ответ 14

Я попробовал так много предложений исправить, но не могу это исправить. Наконец, я решил создать пользовательскую разделительную линию, как показано ниже:

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    var lineView = UIView(frame: CGRectMake(20, cell.contentView.frame.size.height - 1.0, cell.contentView.frame.size.width - 20, 1))

    lineView.backgroundColor = UIColor(red: 170.0/255.0, green: 170.0/255.0, blue: 170.0/255.0, alpha: 1)
    cell.contentView.addSubview(lineView)
}

P/S: пользовательский интерфейс willDisplayCell НЕ cellForRowAtIndexPath

Ответ 15

Совершенно удивительно, что изменение значения ячейки separatorInset взад и вперед, по-видимому, работает:

NSIndexPath *selectedPath = [self.controller.tableView indexPathForSelectedRow];
[self.controller.tableView deselectRowAtIndexPath:selectedPath animated:YES];

UITableViewCell *cell = [self.controller.tableView cellForRowAtIndexPath:selectedPath];
UIEdgeInsets insets = cell.separatorInset;
cell.separatorInset = UIEdgeInsetsMake(0.0, insets.left + 1.0, 0.0, 0.0);
cell.separatorInset = insets;

Ответ 16

Чтобы устранить эту проблему, добавьте пустой footer в viewDidLoad.

UIView *emptyView_ = [[UIView alloc] initWithFrame:CGRectZero];   
emptyView_.backgroundColor = [UIColor clearColor];  
[tableView setTableFooterView:emptyView_];

Пожалуйста, не используйте приведенные выше строки в методе делегата viewForFooterInSection. Средства не реализуют метод viewForFooterInSection.

Ответ 17

У меня также возникла проблема с этим несогласованным отображением строки разделителя в нижней части моего UITableView. Используя пользовательский нижний колонтитул, я смог создать подобную строку и отобразить ее поверх потенциального существующего (что иногда отсутствовало).

Единственная проблема этого решения заключается в том, что Apple может однажды изменить толщину линии

- (UIView*) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    float w = tableView.frame.size.width;

    UIView * footerView =  [[UIView alloc] initWithFrame:CGRectMake(0, 0, w, 1)];
    footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    footerView.clipsToBounds=NO;

    UIView* separatoraddon = [[UIView alloc] initWithFrame:CGRectMake(0, -.5, w, .5)];
    separatoraddon.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    separatoraddon.backgroundColor = tableView.separatorColor;
    [footerView addSubview:separatoraddon];

    return footerView;
}
- (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 1;
}

Ответ 18

Я решил разместить эти строки кода, где обновляется обновление tableview:

self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None;
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine;

Например, в моем случае я разместил их здесь:

tableView.beginUpdates()
tableView.insertRowsAtIndexPaths(insertIndexPaths, withRowAnimation: UITableViewRowAnimation.Fade)
tableView.endUpdates()
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None;
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine;

Ответ 19

Вам нужно удалить ячейку, прежде чем выполнять обновление ячейки. Затем вы можете восстановить выбор.

NSIndexPath *selectedPath = [self.tableview indexPathForSelectedRow];
    [self.tableview deselectRowAtIndexPath:selectedPath animated:NO];
    [self.tableview reloadRowsAtIndexPaths:@[ path ] withRowAnimation:UITableViewRowAnimationNone];
    [self.tableview selectRowAtIndexPath:selectedPath animated:NO scrollPosition:UITableViewScrollPositionNone];

Ответ 20

чтобы расширить ответ на airpaulg, потому что он не полностью работает для меня..

Мне также нужно было реализовать метод heightforfooter для получения высоты

то я заметил, что lightgraycolor слишком темный. Я исправил это, захватив текущий цвет разделителя таблицы и используя это:

UIColor *separatorGray = [self.briefcaseTableView separatorColor]; [footerSeparator setBackgroundColor:separatorGray];

Ответ 21

Я также столкнулся с этой проблемой в нашем проекте. В моем представлении таблицы был tableFooterView, который мог бы сделать это. Я обнаружил, что разделитель ниже последней строки появится, если я удалю этот tableFooterView.

Ответ 22

Для меня изменилась перезагрузка строки, для которой нижняя разделительная строка не появится:

NSIndexPath *indexPath = 
     [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];  
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

Ответ 23

Я решу эту проблему по-другому: добавьте слой, который имеет высоту 0.5px, а его цвет - lightgray в tableview.tableFooterView как его подуровень.

код выглядит так:

UIView *tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 70)];
CALayer *topSeperatorLine = [CALayer layer];
topSeperatorLine.borderWidth = 0.5f;
topSeperatorLine.borderColor = [UIColor lightGrayColor].CGColor;
topSeperatorLine.frame = CGRectMake(0, 0, 320, 0.5f);
[tableFooterView.layer addSublayer:topSeperatorLine];
self.tableView.tableFooterView = tableFooterView;

Ответ 24

В вашем подклассе UITableViewCell реализовайте layoutSubviews и добавьте:

- (void)layoutSubviews{
    [super layoutSubviews]
    for (UIView *subview in self.contentView.superview.subviews) {
        if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) {
            CGRect separatorFrame = subview.frame;
            separatorFrame.size.width = self.frame.size.width;
            subview.frame = separatorFrame;
        }
    }
}

Ответ 25

Как уже упоминалось, эта проблема проявляется различными способами. Я решил проблему с помощью следующего обходного пути:

[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];

Ответ 26

Пройдя ответы и решения, я придумал такие наблюдения:

Это кажется проблематичным как в iOS 7, так и в 8. Я заметил проблему при выборе ячейки из кода в методе viewDidLoad так:

1) обходной путь делал это в viewDidAppear:, если кто-то не возражает против заметной задержки между представлением представления и выбором ячейки

2) второе решение работало для меня, но код выглядит немного хрупким, поскольку он основан на внутренней реализации UITableViewCell

3) добавление собственного разделителя, по-видимому, является самым гибким и лучшим на данный момент, но требует большего количества кодировок:)

Ответ 27

Настройка стиля в viewWillAppear работала для меня.

Ответ 28

Поскольку это все еще проблема с IOS 8, я добавлю свое решение в Swift. Установите для разделителя разделителя таблицы значение none. Затем добавьте этот код в метод делегата cellForRowAtIndexPath. Он добавит хороший разделитель. Оператор if позволяет решить, какие ячейки должны иметь разделитель.

    var separator:UIView!
    if let s = cell.viewWithTag(1000)
    {
        separator = s
    }
    else
    {
        separator = UIView()
        separator.tag = 1000
        separator.setTranslatesAutoresizingMaskIntoConstraints(false)
        cell.addSubview(separator)

        // Swiper constraints
        var leadingConstraint = NSLayoutConstraint(item: separator, attribute: .Leading, relatedBy: .Equal, toItem: cell, attribute: .Leading, multiplier: 1, constant: 15)
        var heightConstraint = NSLayoutConstraint(item: separator, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 0.5)
        var bottomConstraint = NSLayoutConstraint(item: cell, attribute: .Bottom, relatedBy: .Equal, toItem: separator, attribute: .Bottom, multiplier: 1, constant:0)
        var trailingConstraint = NSLayoutConstraint(item: cell, attribute: .Trailing, relatedBy: .Equal, toItem: separator, attribute: .Trailing, multiplier: 1, constant: 15)
        cell.addConstraints([bottomConstraint, leadingConstraint, heightConstraint, trailingConstraint])
    }

    if indexPath.row == 3
    {
        separator.backgroundColor = UIColor.clearColor()
    }
    else
    {
        separator.backgroundColor = UIColor.blackColor()
    }

Ответ 29

Вот мое решение этой проблемы. После того, как вы вставьте свою ячейку (ы), перезагрузите раздел. Если перезагрузка всего раздела слишком интенсивна для вас, просто перезагрузите indexPaths выше и ниже.

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    //  Fix for issue where seperators disappear

    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
}];

[self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];

[CATransaction commit];

Ответ 30

столкнулся с аналогичной проблемой, я обнаружил, что другое хорошее решение, особенно если ваш источник данных невелик, перезагружает tableData при реализации метода -(void)scrollViewDidScroll:(UIScrollView *)scrollView, вот пример:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
      if (scrollView == self.tableView1) {
          [self.tableView1 reloadData];
      }

      else {
          [self.tableView2 reloadData];
      }
}

Вы также можете просто перезагрузить невидимые данные на основе видимого источника данных, но для этого требуется еще немного взлома.

Имейте в виду, что эта функция делегата относится к протоколу UITableViewDelegate!

Надеюсь, что это поможет!