Подтвердить что ты не робот

UITableView: сбой при добавлении нижнего колонтитула раздела в пустой раздел

Это первый раз, когда я задаю вопрос здесь, но я должен сказать, что этот сайт был огромной помощью для меня за последние пару месяцев (iphone-dev-wise), и я благодарю вас за это.

Однако я не нашел решения для этой проблемы: У меня есть UITableView с 2 разделами и без строк, когда приложение запускается в первый раз. Пользователь может заполнить разделы позже, как пожелает (содержание здесь не актуально). UITableView выглядит хорошо, когда заполняется строками, но выглядит довольно уродливым, когда его нет (2 секции заголовка склеиваются вместе без пробела между ними). Вот почему я хотел бы добавить красивое представление "Нет строк" ​​между ними, когда нет строки.

Я использовал viewForFooterInSection:

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

if(section == 0)
{
    if([firstSectionArray count] == 0)
        return 44;
    else 
        return 0;
}

return 0;

}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{

    if(section == 0)
    {
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 50, 44)];
        label.backgroundColor = [UIColor clearColor];
        label.textColor = [UIColor colorWithWhite:0.6 alpha:1.0];
        label.textAlignment = UITextAlignmentCenter;
        label.lineBreakMode = UILineBreakModeWordWrap; 
        label.numberOfLines = 0;
        label.text = @"No row";
        return [label autorelease];
    }

    return nil;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if(section == 0)
    {
        return [firstSectionArray count];
    }
    return [secondSectionArray count];
}

Это отлично работает: просмотр нижнего колонтитула появляется только тогда, когда в разделе 0 нет строки. Но мое приложение падает, когда я вхожу в режим редактирования и удаляю последнюю строку в разделе 0:

Ошибка утверждения в - [UIViewAnimation initWithView: indexPath: endRect: endAlpha: startFraction: endFraction: curve: animateFromCurrentPosition: shouldDeleteAfterAnimation: edit:] Завершение приложения из-за неперехваченного исключения "NSInternalInconsistencyException", причина: "Столбцы стоп-кадра должны быть больше, чем начальная доля"

Этого не происходит, если в разделе 0 есть несколько строк. Это происходит только в том случае, если осталось только одна строка.

Здесь код для режима редактирования:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    // If row is deleted, remove it from the list.
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Find the book at the deleted row, and remove from application delegate array.

        if(indexPath.section == 0)
        { [firstSectionArray removeObjectAtIndex:indexPath.row]; }
        else 
        { [secondSectionArray removeObjectAtIndex:indexPath.row]; }

        // Animate the deletion from the table.
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                             withRowAnimation:UITableViewRowAnimationBottom];


        [tableView reloadData];

    }
}

Кто-нибудь знает, почему это происходит? Благодаря

4b9b3361

Ответ 1

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

Две идеи для вас:

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

2. вместо удаления единственной строки вашей таблицы, когда нет "реальных" строк данных, пусть таблица все еще имеет numberOfRowsInSection return 1 и создает поддельную ячейку "без данных" вместо использования нижнего колонтитула таблицы для случая "без данных".

Это один из тех случаев, когда вам просто нужно признать, что Apple написала половину вашей программы для вас, и вы должны соответствовать некоторым вариантам, которые сделал ваш соавтор, нравится вам это или нет.

Ответ 2

  • сделать пустой раздел
  • используйте заголовок таблицы в этом разделе вместо нижнего колонтитула в первом разделе
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (section != OTHER_SECTION_INDEX) {
        return nil;
    }
    //your code here
}

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section != OTHER_SECTION_INDEX) {
        return 0;
    }
    //your code
}

Ответ 3

нет необходимости вызывать как deleteRowsAtIndexPaths:withAnimation:, так и reloadData на tableView.

проблема, которую вы видите, - это проблема, которую я вижу в вызове deleteRowsAtIndexPaths:withAnimation:, и, таким образом, для вас она никогда не попадает в reloadData.

более простое решение, связанное с необходимостью создания новых ячеек, управления ими, работы со всеми местами, в которых должна обрабатываться другая ячейка, заключается в использовании reloadSections:withAnimation: при работе с разделом, который идет от 0 до 1 строка или от 1 до 0 строк.

то есть. замените следующие строки кода:

        if(indexPath.section == 0)
        { [firstSectionArray removeObjectAtIndex:indexPath.row]; }
        else 
        { [secondSectionArray removeObjectAtIndex:indexPath.row]; }

        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationBottom];

со следующим

        BOOL useReloadSection;
        if (indexPath.section == 0)
        {
            [firstSectionArray removeObjectAtIndex:indexPath.row];
            useReloadSection = 0 == firstSectionArray.count;
        }
        else 
        {
            [secondSectionArray removeObjectAtIndex:indexPath.row];
            useReloadSection = 0 == secondSectionArray.count;
        }

        if (useReloadSection)
            [tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section]
                     withRowAnimation:UITableViewRowAnimationBottom];
        else
            [tableView deleteRowsAtIndexPaths:@[indexPath]
                             withRowAnimation:UITableViewRowAnimationBottom];

Ответ 4

Я столкнулся с одним и тем же сбоем, похоже, что это ошибка в ОС.

Мой конкретный пример использования относится к UITableView с разворачиваемыми/расширяемыми разделами. Мне нужны разделители разделов (это то, что я использовал нижний колонтитул раздела), но не разделители строк (не могу просто использовать разделитель ячеек).

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

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    CGRect frame = (CGRect){0, 0, self.view.bounds.size.width, 1};
    UIView *view = [[UIView alloc] initWithFrame:frame];
    view.backgroundColor = [UIColor commentReplyBackground];

    return view;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 1.0f;
}

Ответ 5

Для тех, кому еще нужен нижний колонтитул раздела, вы также можете попробовать изменить стиль TableView на UITableViewStyleGrouped. Это, похоже, обходит проблему. Чтобы получить тот же внешний вид, вам просто нужно установить все свои нижние колонтитулы и заголовки в CGFLOAT_MIN.