Змініть поведінку прокрутки за замовчуванням заголовка розділу UITableView


147

У мене є UITableView з двома розділами. Це простий вид таблиці. Я використовую viewForHeaderInSection, щоб створити власні подання для цих заголовків. Все йде нормально.

Поведінка прокрутки за замовчуванням полягає в тому, що, коли зустрічається секція, заголовок розділу залишається закріпленим нижче смуги Nav, доки наступний розділ не прокручується.

Моє запитання таке: чи можу я змінити поведінку за замовчуванням, щоб заголовки розділів НЕ трималися на якорі вгорі, а, скоріше, прокручувались під панеллю навігації з рештою рядків розділу?

Невже я пропускаю щось очевидне?

Дякую.


1
Це, мабуть, одне з найкращих письмових питань на цьому сайті! :) Дякую.
Fattie

1
Перевірте тут правильний шлях для досягнення цього ефекту stackoverflow.com/a/13735238/1880899
Sumit Anantwar

Відповіді:


175

Я вирішив цю проблему, щоб відрегулювати в 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, відчуття пальця здається ідеальним або майже ідеальним.}


1
Ідеальне рішення, ніж вище.
prathumca

4
Дякую! Це ідеальне рішення. У вас є рішення для колонтитулу секції?
Туан Нгуен

12
Це рішення не обробляє належну версію меню, що належить прокручувати до початку списку.
Рейд Елліс

якщо вам потрібна така ж поведінка для подання нижнього колонтитулу розділу, просто змініть останній рядок, як цей: scrollView.contentInset = UIEdgeInsetsMake (0, 0, sectionHeaderHeight, 0)
alex

Цього, здається, достатньо: scrollView.contentInset = UIEdgeInsetsMake (scrollView.contentOffset.y> = 0? -ScrollView.contentOffset.y: 0, 0, 0, 0);
MacMark

85

Ви також можете додати розділ з нульовими рядками вгорі і просто використовувати колонтитул попереднього розділу в якості заголовка для наступного.


13
У моєму випадку, коли у мене більше 2-х секцій, нижній колонтитул буде закріплюватися внизу ..
Джозеф Лін

3
Це творчо, але вам потрібно налаштувати indexPath, якщо для завантаження таблиці використовуєте NSFetchedResultsController.
XJones

+1 на сьогодні найкраще рішення - реалізував мене, як 3 лінії!
Джон

Блискучий Блискучий Блискучий :-)
iphonic

Як би це працювало для нижнього колонтитулу, який закріплює? Буду вдячний за допомогу! Дякую
darwindeeds

36

Якби це я робив, я би скористався тим, що UITableViews в стилі Plain мають клейкі заголовки, а в стилі Grouped - ні. Я, мабуть, хоч би спробував використовувати користувальницьку клітинку таблиці, щоб імітувати зовнішній вигляд звичайних комірок у згрупованій таблиці.

Я насправді цього не пробував, щоб це не спрацювало, але я б радив це зробити.


Напевно, спрацювало б, але це було випробувано? І, здається, багато роботи, коли відповідь @ voidStern прекрасно працює !!
Бентфорд

відповідь voidStern не працює для мене, коли у мене є більше двох розділів. Відповідь Коліна простіша / елегантніша, без необхідності вручну змінювати номер розділу та додавати кількість секцій.
Джозеф Лін

Поради: використовуйте tableView.separatorColor = [UIColor clearColor];для імітації простого вигляду таблиці.
Джозеф Лін

3
Я спробував це зробити, але коли я не зміг зробити так, щоб об'єднані клітинки таблиці виглядали як звичайні, тобто видалити лівий і правий край з обох боків комірок. Як ти це зробив?
Адам Картер

1
Дякую вам за те, що ви зрозуміли, що стосується UITableViewStyle, тобто згрупованого та простого, який вирішує, чи буде заголовок / колонтитул розділу tableview липким чи ні. Велике спасибі @Colin Barrett
Dhaval H. Nena

28

Я знаю, що приходить пізно, але я знайшов остаточне рішення!

Що ви хочете зробити, це якщо у вас є 10 розділів, нехай даніSource повернуть 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


чудова ідея. але якщо у вас є заголовки індексу розділів, я підозрюю, що це зіпсує їх.
roocell

чому? ви можете зробити те ж саме з заголовками розділів. Просто пам’ятайте нуль для непарних чисел та заголовок для парного числа.
LocoMike

1
так - цей метод чудово працює. Це було багато бухгалтерії (можливо, це стосується того, як я маю отримати заголовки розділів), але це спрацювало. Хитрість полягає в тому, що числоOfRowsInSection і cellForRowAtIndexPath використовує if (розділ% 2! = 0 && розділ! = 0), тоді як заголовокForHeaderInSection та інші функції індексу розділу використовують, якщо (section% 2 == 0)
roocell

оригінатор повинен вибрати це як відповідь. Було б чудово, якби існував спосіб підкласу uitableview, щоб автоматично закріплювати заголовки розділів.
roocell

Це працювало найкраще для мене. Спершу я спробував рішення @ Colin, але він не спрацював із сильно налаштованим, UITableViewякий я використовую.
кубі

15

Для вирішення цієї проблеми не хакітним способом потрібно зробити кілька речей:

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

(+1) @Neil, я спробував вашу відповідь, але, на жаль, для UITableViewStyleGroupedкомірок таблиці є додаткові поля, які змінюють їх вирівнювання із заголовком. Це проблема, коли ви хочете зобразити таблицю з декількома стовпцями та використовувати заголовок для показу заголовків стовпців (а потім окремі записи таблиці вирівняти з цими заголовками).
brainjam

15

Спочатку розміщено тут , швидке рішення за допомогою ІБ. Те ж саме можна зробити програмно, хоча досить просто.

Напевно, простіший спосіб досягти цього (використовуючи ІБ):

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

  1. Встановіть висоту перегляду заголовка на 100 пікс
  2. Встановіть вміст перегляду таблиці (Inset) (вгорі) на -100
  3. Тепер заголовки розділів прокручуватимуться так само, як і будь-яка звичайна комірка.

Деякі люди коментують, що це рішення ховає перший заголовок, однак я не помітив жодної такої проблеми. Це прекрасно працювало для мене і було, безумовно, найпростішим рішенням, яке я бачив досі.


Зверніть увагу, що ви, мабуть, повинні встановити подання для використання фонового кольору прозорого кольору, інакше, якщо прокрутити повз верхню частину, ви побачите білий відбій.
Док

3
Це ховає мій перший заголовок
Leena

Leena, на якій версії iOS ти працюєш? Чи подання UITableViewController, або UIView з UITableView у ньому? Я не впевнений, чому для деяких людей це рішення ховає перший заголовок, тому я намагаюся знайти будь-які розбіжності.
Док

Це рішення ідеально. Я шукаю нескінченний зовнішній вигляд фонової клітини верхнього і нижнього - це цілком досягає цього. Приємно!
Тейлор Халлідей

Це рішення відмінне. Простіше виконати, ніж інші відповіді в цій темі. На мою думку, це має бути прийнятою відповіддю.
Джон Роджерс

15

Я не був задоволений описаними тут рішеннями, тому спробував їх поєднати. Результат - наступний код, натхненний @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)]];

Це було найпростіше рішення, яке я знайшов.
Зорайр

Це працювало для мене на iOS9.2, тож, хоча відповідь старіша, вона все-таки справедлива. І це не приховувало заголовок першого розділу. Працює та працює чудово.
idStar

Ідеально. Якщо у вашому перегляді таблиці вже є заголовок, просто збільшити його висоту на зміщення, а потім збільшити верхню константу обмеження вмісту заголовка, щоб змістити вміст у вихідне положення
Джейсон

14

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

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

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

UITableViewStylePlain - звичайний вид таблиці. Будь-які заголовки або колонтитули розділів відображаються як вбудовані роздільники та плавають, коли подається таблиця.

UITableViewStyleGrouped - вид таблиці, в розділах якого представлені окремі групи рядків. Заголовки та колонтитули секцій не плавають.


чудова відповідь, працював на мене. не потрібно ніякої роботи навколо
Шамс Ахмед

9

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

Виберіть стиль групового перегляду таблиці в інспекторі атрибутів таблиціView в дошці повідомлень.


5

Встановіть headerView таблиці з прозорим видом з однаковою висотою заголовка в розділі подання. Також ініціюйте перегляд таблиці з рамкою на висоті.

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

4

Я знайшов альтернативне рішення, використовуйте першу комірку кожного розділу замість реальної секції заголовка; це рішення не виглядає настільки чистим, але працює так чудово, ви можете використовувати визначену прототипну комірку для розділу заголовків та в методі cellForRowAtIndexPath запитайте indexPath.row == 0, якщо це правда, використовуйте прототип прототипу комірця розділу, в іншому випадку використовуйте стандартну комітку прототипу за замовчуванням.


Якщо ви все ще хочете працювати з indexPath.row& indexPath.section, переконайтеся , що ви повертаєте висоту 0.0fдля , - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionщоб ваші заголовки невидимі.
Суп

4

Змініть свій стиль TableView:

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

Відповідно до документації щодо Apple для UITableView:

UITableViewStylePlain - звичайний вид таблиці. Будь-які заголовки або колонтитули розділів відображаються як вбудовані роздільники та плавають, коли подається таблиця.

UITableViewStyleGrouped - вид таблиці, в розділах якого представлені окремі групи рядків. Заголовки та колонтитули секцій не плавають. Сподіваюся, що ця невелика зміна допоможе вам ..


2

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


Це найкраще рішення, особливо якщо клітинки є на замовлення, здається, що вони просто припиняють "утримувати" заголовок розділу, коли прокрутка потрапляє на верхню частину.
Перероблена сталь

1

Призначте негативну вставку для таблиціView. Якщо у вас є 22px заголовки високого розміру, і ви не хочете, щоб вони були липкими, відразу після перезавантаженняДані додайте:

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

Працює як шарм для мене. Працює і для нижнього колонтитулу секцій, просто призначте негативну вставку на нижній частині.


Це просто відсікає перший заголовок ??
cannyboy

Працювали для мене чудово !! Спасибі
Даніель

0

Я додаю таблицю до перегляду прокрутки, і це, здається, працює добре.


0

Перевірте мою відповідь тут . Це найпростіший спосіб реалізувати заголовки не плаваючого розділу без жодних злому.


0

@ Відповідь 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;
    ...
}

0

Швидка версія відповіді @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)
    }
}

-2

Я дізнався, що лише встановлення властивості tableHeaderView це робить, тобто:

 tableView.tableHeaderView = customView;

і це все.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.