Изменить стандартное поведение прокрутки заголовка раздела UITableView

У меня есть UITableView с двумя разделами. Это простой вид таблицы. Я использую viewForHeaderInSection для создания пользовательских представлений для этих заголовков. Все идет нормально.

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

У меня такой вопрос: могу ли я изменить поведение по умолчанию, чтобы заголовки разделов НЕ оставались на якоре сверху, а прокручивались под панелью навигации с остальными строками разделов?

Я что-то упускаю из виду?

Благодарю.

20 ответов

Я решил эту проблему, чтобы настроить contentOffset в соответствии с contentInset в UITableViewControllerDelegate (продолжается UIScrollViewDelegate) как это:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
       CGFloat sectionHeaderHeight = 40;
   if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
       scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
   } else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
       scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
   }
}

Единственная проблема здесь в том, что при прокрутке назад к вершине он немного теряет отскок.


{ПРИМЕЧАНИЕ: "40" должно быть точной высотой ВАШЕГО заголовка секции 0. Если вы используете число, которое больше, чем высота заголовка вашего раздела 0, вы увидите, что это влияет на ощущение пальца (попробуйте как "1000", и вы увидите, что поведение отскока вверху странно). если число соответствует высоте заголовка вашего раздела 0, ощущение пальца кажется либо идеальным, либо почти идеальным.}

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

Если бы я этим занимался, я бы использовал тот факт, что UITableViews в стиле Plain имеют липкие заголовки, а заголовки в стиле Grouped - нет. Я бы, по крайней мере, попытался бы использовать пользовательскую ячейку таблицы, чтобы имитировать появление простых ячеек в сгруппированной таблице.

Я на самом деле не пробовал это, так что это может не сработать, но я бы предложил это сделать.

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

Что вы хотите сделать, если у вас есть 10 разделов, пусть dataSource возвращает 20. Используйте четные числа для заголовков разделов и нечетные числа для содержимого разделов. что-то вроде этого

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section%2 == 0) {
        return 0;
    }else {
        return 5;
    }
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (section%2 == 0) {
        return [NSString stringWithFormat:@"%i", section+1];
    }else {
        return nil;
    }
}

Вуаля!:D

Первоначально опубликовано здесь, быстрое решение с использованием IB. То же самое можно сделать программно, хотя и довольно просто.

Вероятно, более простой способ добиться этого (с помощью IB):

Перетащите UIView на свой TableView, чтобы сделать его представлением заголовка.

  1. Установите высоту представления этого заголовка на 100 пикселей
  2. Установите для tableView contentInset (top) значение -100
  3. Заголовки разделов теперь будут прокручиваться, как и любая обычная ячейка.

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

Есть несколько вещей, которые нужно сделать, чтобы решить эту проблему не хакерским способом:

  1. Установите стиль представления таблицы на UITableViewStyleGrouped
  2. Установить вид таблицы backgroundColor в [UIColor clearColor]
  3. Установить backgroundView в каждой ячейке табличного представления в пустое представление с backgroundColor [UIColor clearColor]
  4. При необходимости установите вид таблицы rowHeight или переопределить tableView:heightForRowAtIndexPath: если отдельные строки имеют разную высоту.

Просто измените стиль TableView:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

UITableViewStyle Документация:

UITableViewStylePlain - простое табличное представление. Любые верхние или нижние колонтитулы отображаются как встроенные разделители и плавают при прокрутке табличного представления.

UITableViewStyleGrouped - табличное представление, разделы которого представляют различные группы строк. Верхние и нижние колонтитулы раздела не плавают.

Я не был доволен решениями, описанными здесь до сих пор, поэтому я попытался объединить их. В результате получается следующий код, вдохновленный @awulf и @cescofry. Это работает для меня, потому что у меня нет реального заголовка табличного представления. Если у вас уже есть заголовок табличного представления, возможно, вам придется настроить высоту.

// Set the edge inset
self.tableView.contentInset = UIEdgeInsetsMake(-23.0f, 0, 0, 0);

// Add a transparent UIView with the height of the section header (ARC enabled)
[self.tableView setTableHeaderView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 23.0f)]];

Выберите сгруппированный стиль TableView

Выберите стиль сгруппированного табличного представления в Инспекторе атрибутов вашего tableView в раскадровке.

Установите заголовок таблицы с прозрачным представлением с той же высотой заголовка в разрезе. Также инициируйте просмотр таблицы с помощью y-frame в -height.

self.tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, - height, 300, 400)];

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)] autorelease];
[self.tableView setTableHeaderView:headerView];

Измените ваш стиль TableView:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

Согласно документации Apple для UITableView:

UITableViewStylePlain - простое табличное представление. Любые верхние или нижние колонтитулы отображаются как встроенные разделители и плавают при прокрутке табличного представления.

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

Я нашел альтернативное решение: использовать первую ячейку каждого раздела вместо реального раздела заголовка, это решение не выглядит таким чистым, но работает настолько хорошо, что вы можете использовать определенную ячейку прототипа для раздела заголовков и в методе cellForRowAtIndexPath запросите indexPath.row==0, если true, используйте ячейку прототипа раздела заголовка, иначе используйте вашу ячейку прототипа по умолчанию.

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

Назначьте отрицательную вставку для вашего tableView. Если у вас есть заголовки секций высотой 22px, и вы не хотите, чтобы они были липкими, сразу после перезагрузки Data add:

self.tableView.contentInset = UIEdgeInsetsMake(-22, 0, 0, 0); 
self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height+22); 

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

Измените ваш стиль TableView:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

Согласно документации Apple для UITableView:

UITableViewStylePlain- A plain table view. Any section headers or footers are displayed as inline separators and float when the table view is scrolled.

UITableViewStyleGrouped- A table view whose sections present distinct groups of rows. The section headers and footers do not float.
Hope this small change will help you ..

Проверьте мой ответ здесь. Это самый простой способ реализовать заголовки не плавающих разделов без каких-либо взломов.

Ответ @LocoMike лучше всего подходил для моего tableView, однако он сломался и при использовании нижних колонтитулов. Итак, это исправленное решение при использовании верхних и нижних колонтитулов:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return (self.sections.count + 1) * 3;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section % 3 != 1) {
        return 0;
    }
    section = section / 3;
    ...
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return 0;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return 0;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    int section = indexPath.section;
    section = section / 3;
    ...
}

Я добавляю таблицу в представление прокрутки, и это, кажется, работает хорошо.

Swift версия ответа @awulf, которая прекрасно работает!

func scrollViewDidScroll(scrollView: UIScrollView) {
    let sectionHeight: CGFloat = 80
    if scrollView.contentOffset.y <= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake( -scrollView.contentOffset.y, 0, 0, 0)
    }else if scrollView.contentOffset.y >= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake(-sectionHeight, 0, 0, 0)
    }
}

Я узнал, что просто установка свойства tableHeaderView делает это, то есть:

 tableView.tableHeaderView = customView;

и это все.

Другие вопросы по тегам