UITableView встановлений на статичні комірки. Чи можливо приховати деякі комірки програмно?


132

UITableView встановити на статичні комірки.

Чи можливо приховати деякі комірки програмно?

Відповіді:


48

Ви шукаєте це рішення:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

яка може показувати / приховувати / перезавантажувати будь-які статичні комірки з анімацією або без неї!

[self cell:self.outletToMyStaticCell1 setHidden:hide]; 
[self cell:self.outletToMyStaticCell2 setHidden:hide]; 
[self reloadDataAnimated:YES];

Зауважте, що завжди використовувати лише (reloadDataAnimated: ТАК / НІ) (не дзвоніть [self.tableView reloadData] безпосередньо)

Це не використовує хакі-рішення із встановленням висоти 0 і дозволяє анімувати зміни та приховувати цілі секції


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

як ви маєте на увазі прогалини? ви можете краще описати ситуацію, можливо, безпосередньо на github? ти запустив зразок?
Пітер Лапісу

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

1
перевірте зразок, там було більше оновлення, можливо, у вас був якийсь старий код ... для мене ідеально підходить
Пітер Лапис

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

164

Щоб приховати статичні комірки в UITable:

  1. Додайте цей метод :

У вашому класі делегата контролера UITableView:

Завдання-C:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if(cell == self.cellYouWantToHide)
        return 0; //set the hidden cell's height to 0

    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

Швидкий:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

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

  1. У дизайнері створіть розетку для комірок, які ви хочете приховати. Розетка для однієї такої комірки вище називається "cellYouWantToHide".
  2. Установіть прапорець "Кліп підказок" в IB для комірок, які ви хочете приховати. У клітинках, які ви ховаєте, потрібно мати ClipToBounds = ТАК. Інакше текст накопичиться в UITableView.

10
Приємне рішення. Щоб уникнути ClipToBoundsпроблеми, ви також можете встановити клітинку на приховану. Мені це здасться чистішим. ;-)
MonsieurDart

13
+1 для ClipToBounds = ТАК. Рішення чисел в інших потоках пропустили це.
Джефф

2
Чудова ідея. Це найпростіше рішення, яке я знайшов. Інші рішення мали код у двох або більше місцях. BTW, в IB, ClipToBounds занесений до "Підзагляди кліпу".
VaporwareWolf

1
Трохи виправлення, використовуйте self .cellYouWantToHide замість цього .cellYouWantToHide.
Золтан Вінклер

2
не створюючи об’єкт клітинки, ми також можемо використовувати "index.row", щоб приховати "uitableviewcell"
g212gs

38

Найкращий спосіб описаний у наступному блозі http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

Створіть свій перегляд статичної таблиці як звичайний для побудови інтерфейсу - у комплекті з усіма потенційно прихованими клітинками. Але є одне, що ви повинні зробити для кожної потенційної комірки, яку ви хочете приховати, - перевірте властивість кліпу "Підвідмірки" клітини, інакше вміст комірки не зникне при спробі приховати її (зменшуючи висоту - ще пізніше).

Так - у вас є перемикач у комірці, і комутатор повинен ховати та показувати деякі статичні комірки. Підключіть це до IBAction і там зробіть це:

[self.tableView beginUpdates];
[self.tableView endUpdates];

Це дає вам приємну анімацію для клітин, які з’являються та зникають. Тепер застосуйте такий метод делегування подання таблиці:

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need
    // Show or hide cell
        if (self.mySwitch.on) {
            return 44; // Show the cell - adjust the height as you need
        } else {
            return 0; // Hide the cell
        }
   }
   return 44;
}

І це все. Перемістіть перемикач, і комірка ховається і знову з’являється з приємною, плавною анімацією.


Оновлення: вам також потрібно встановити ярлик стільника таким чином, щоб приховати / показати з вами клітинку приховати / показати, інакше мітки зроблять безлад.
Мохамед Салех

1
Слід зазначити, що якщо будь-який UIView у вмісті вашої статичної комірки має обмеження щодо cell.content, ви можете отримати помилку виконання, якщо ці обмеження недійсні для вашої нової висоти комірки.
Педро Борхес

1
Найкраща відповідь. Дякую.
Ерік Чен

1
Я знав, що ця хитрість працює з динамічним змістом. Дуже добре працює і зі статикою. Так просто теж.
Мурашки

2
Це дійсно працює, але для покриття пропущеної точки: якщо рядок, який потрібно приховати / показати, містить вибір дати, виконуючи лише [self.tableView beginUpdates]; [self.tableView endUpdates]; все одно залишать глюк, ховаючи його. Щоб усунути глюк, слід зателефонувати [self.tableView reloadRowsAtIndexPaths: @ [indexPathOfTargetRow] withRowAnimation: UITableViewRowAnimationNone]; Також зауважте, що анімація рядків тут якось "відключена".
Кріс

34

Моє рішення йде в аналогічний напрям, як Гарет, хоча деякі речі я роблю інакше.

Ось:

1. Сховати клітини

Немає можливості безпосередньо приховати клітини. UITableViewControllerє джерелом даних, яке забезпечує статичні комірки, і в даний час немає способу сказати це "не надавати клітинку x". Тож ми маємо надати власне джерело даних, яке делегує UITableViewController, щоб отримати статичні комірки.

Найпростіше - це підклас UITableViewControllerта перекриття всіх методів, які повинні поводитися по-різному, приховуючи клітини .

У найпростішому випадку (таблиця з одним розділом, всі осередки мають однакову висоту), це піде так:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section    
{
    return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Recalculate indexPath based on hidden cells
    indexPath = [self offsetIndexPath:indexPath];

    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
    int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
    int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
    int offsetRow = indexPath.row + numberOfCellsHiddenAbove;

    return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}

Якщо у вашій таблиці є декілька розділів або комірки мають різну висоту, вам потрібно змінити більше методів. Тут застосовується той самий принцип: Вам потрібно зрушити indexPath, розділ і рядок перед делегацією в super.

Також майте на увазі, що параметр indexPath для подібних методів didSelectRowAtIndexPath:буде різним для однієї комірки, залежно від стану (тобто кількості прихованих комірок). Тому, мабуть, є хорошою ідеєю завжди компенсувати будь-який параметр indexPath і працювати з цими значеннями.

2. Анімувати зміни

Як уже заявив Гарет, ви отримуєте основні проблеми, якщо анімувати зміни за допомогою reloadSections:withRowAnimation:методу.

Я дізнався, що якщо ви reloadData:відразу зателефонуєте , анімація значно покращиться (залишилися лише незначні глюки). Таблиця відображається правильно після анімації.

Отже, що я роблю, це:

- (void)changeState
{
     // Change state so cells are hidden/unhidden
     ...

    // Reload all sections
    NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];

    [tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView reloadData];
}

2
Благослови вас, мила мила людина.
гуптрон

Ви знайшли рішення для незначних збоїв в анімації? для мене лінії сепаратора між клітинками не будуть правильно анімувати, а id - скоріше не використовувати анімацію, ніж гліковану. чудове рішення, хоча!
Максиміліан Кьорнер

Моя проблема полягає в тому, що статичні осередки numberOfRowsInSection:викликаються лише при першому завантаженні таблиці. Коли я дзвоню [self.tableView reloadData] - numberOfRowsInSection:більше ніколи не дзвоню . Тільки cellForRowAtIndexPath:називається. Що я пропускаю?
Роман

13
  1. У дизайнері створіть розетку для комірок, які ви хочете приховати. Наприклад, ви хочете приховати 'cellOne', тому в viewDidLoad () зробіть це

cellOneOutlet.hidden = вірно

тепер замініть нижченаведений метод, перевірте, який стан комірки приховано, і поверніть висоту 0 для цих комірок. Це один з багатьох способів швидко приховати будь-яку клітинку в статичну tableView.

override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat 
{

let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)

        if tableViewCell.hidden == true
        {
            return 0
        }
        else{
             return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
        }

}

Найкраще рішення поки що!
дердіда

додайте tableView.reloadData () після внесення змін і це ідеально. Заощадило мені багато зусиль для зміни рішення! дякую
Шаян C

1
Swift 4 не дозволяє мені користуватися let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath). Я припускаю, що це замінено на let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath).
Кліфтон Лабрум

Оскільки я використовую статичні комірки на а UITableViewController, я не маю жодних UITableViewметодів делегування. Для того, щоб змусити його зателефонувати heightForRow, чи потрібно також використовувати інші методи?
Кліфтон Лабрум

@CliftonLabrum ні, ви можете змінити лише цей метод.
Олександр Єршов

11

Я придумав альтернативу, яка фактично приховує розділи та не видаляє їх. Я спробував підхід @ henning77, але в мене виникли проблеми, коли я змінив кількість розділів статичного UITableView. Цей метод спрацював для мене дуже добре, але я в першу чергу намагаюся приховати розділи замість рядків. Я ледь вдало видаляю рядки, але це набагато грізніше, тому я спробував згрупувати речі в розділи, які мені потрібно показати або приховати. Ось приклад того, як я приховую розділи:

Спочатку я оголошую властивість NSMutableArray

@property (nonatomic, strong) NSMutableArray *hiddenSections;

У viewDidLoad (або після запиту даних) ви можете додати до масиву розділи, які ви хочете приховати.

- (void)viewDidLoad
{
    hiddenSections = [NSMutableArray new];

    if(some piece of data is empty){
        // Add index of section that should be hidden
        [self.hiddenSections addObject:[NSNumber numberWithInt:1]];
    }

    ... add as many sections to the array as needed

    [self.tableView reloadData];
}

Потім реалізуйте наступні методи делегування TableView

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return nil;
    }

    return [super tableView:tableView titleForHeaderInSection:section];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        return 0;
    }

    return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        [cell setHidden:YES];
    }
}

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

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
{
    CGFloat height = [super tableView:tableView heightForHeaderInSection:section];

    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        height = 1; // Can't be zero
    }
    else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
        // Adjust height for previous hidden sections
        CGFloat adjust = 0;

        for(int i = (section - 1); i >= 0; i--){
            if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
                adjust = adjust + 2;
            }
            else {
                break;
            }
        }

        if(adjust > 0)
        {                
            if(height == -1){
                height = self.tableView.sectionHeaderHeight;
            }

            height = height - adjust;

            if(height < 1){
                height = 1;
            }
        }
    }

    return height;
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
{   
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return 1;
    }
    return [super tableView:tableView heightForFooterInSection:section];
}

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];

    if(self.organization != nil){
        if(section == 5){ // Contact
            if([self.organization objectForKey:@"Phone"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"Email"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"City"] == [NSNull null]){     
                rows--;
            }
        }
    }

    return rows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

Використовуйте цей offsetIndexPath для обчислення indexPath для рядків, де ви умовно видаляєте рядки. Не потрібен, якщо ви ховаєте лише секції

- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
    int row = indexPath.row;

    if(self.organization != nil){
        if(indexPath.section == 5){
            // Adjust row to return based on which rows before are hidden
            if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){     
                row = row + 2;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
        }
    }

    NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];

    return offsetPath;
}

Існує дуже багато методів переоцінки, але мені подобається цей підхід - це повторне використання. Налаштуйте масив hiddenSections, додайте до нього, і він приховає правильні розділи. Ховаючи ряди, це трохи хитріше, але можливо. Ми не можемо просто встановити висоту рядків, які ми хочемо приховати до 0, якщо ми використовуємо згрупований UITableView, оскільки межі не будуть виведені правильно.


1
Я б , ймовірно , використовувати NSMutableSetдля hiddenSectionsзамість. Це набагато швидше, оскільки ви в основному тестуєте на членство.
pixelfreak

Гарна відповідь, Остін. Я проголосував за цю відповідь і буду використовувати це як орієнтир для моїх проектів у майбутньому. pixelfreak також робить хорошу точку про використання NSMutableSetдля hiddenSections, хоча я розумію , що точка вашої відповіді , був більш концептуальним , ніж ніт-розбірливі в тому , який тип структури даних , ви повинні використовувати.
BigSauce

10

Виявляється, ви можете сховати і показати комірки в статичному UITableView - і з анімацією. І це не так важко здійснити.

Демонстраційний проект

Відео демонстраційного проекту

Суть:

  1. Use tableView:heightForRowAtIndexPath: щоб динамічно вказати висоту комірок на основі певного стану.
  2. Коли стан змінюється, анімовані комірки відображаються / приховуються за допомогою виклику tableView.beginUpdates();tableView.endUpdates()
  3. Не дзвоніть tableView.cellForRowAtIndexPath:всередину tableView:heightForRowAtIndexPath:. Використовуйте кешовані indexPaths для диференціації комірок.
  4. Не ховайте клітини. Встановіть замість властивості "Кліп підпрограм" у Xcode.
  5. Використовуйте власні клітинки (не звичайні тощо), щоб отримати хорошу анімацію приховування. Також правильно обробіть автоматичний макет у випадку, коли висота комірки == 0.

Більше інформації в моєму блозі (російська мова)


1
Цей момент був важливим для мене: "Не приховувати клітини. Замість цього встановіть властивість" Clip Subviews "у Xcode."
балкот

8

Так, це, безумовно, можливо, хоча я зараз борюся з тим же питанням. Мені вдалося змусити клітинки приховати, і все працює нормально, але наразі я не можу зробити так, щоб річ анімувалась акуратно. Ось що я знайшов:

Я приховую рядки на основі стану вимикача ON / OFF у першому рядку першого розділу. Якщо перемикач увімкнено, під ним у цьому ж розділі знаходиться 1 ряд, інакше є 2 різних рядки.

У мене є селектор, який викликається, коли перемикач перемикається, і я встановлюю змінну, щоб вказати, у якому стані я перебуваю. Потім я закликаю:

[[self tableView] reloadData];

Я переосмислюю функцію tableView: willDisplayCell: forRowAtIndexPath: і якщо комірка повинна бути прихованою, я роблю це:

[cell setHidden:YES];

Це приховує клітинку та її вміст, але не прибирає місця, яке вона займає.

Щоб вилучити пробіл, замініть функцію tableView: heightForRowAtIndexPath: і поверніть 0 для рядків, які слід приховати.

Вам також потрібно замінити tableView: numberOfRowsInSection: і повернути кількість рядків у цьому розділі. Тут ви повинні зробити щось дивне, щоб, якщо ваш стіл є згрупованим стилем, закруглені кути трапляються на правильних клітинках. У моїй статичній таблиці є повний набір комірок для розділу, тому є перша комірка, що містить опцію, потім 1 комірка для параметрів стану ВКЛ та ще 2 комірки для опцій стану ВИМКН, загалом 4 комірки. Коли параметр увімкнено, мені потрібно повернути 4, сюди входить прихований варіант, щоб останній варіант, що відображається, мав закруглене поле. Коли параметр вимкнено, останні два варіанти не відображаються, тому я повертаюся 2. Це все відчуває незграбність. Вибачте, якщо це не дуже зрозуміло, його складно описати. Просто для ілюстрації налаштування, це побудова розділу таблиці в IB:

  • Рядок 0: Варіант із перемикачем ON / OFF
  • Рядок 1: відображається, коли параметр увімкнено
  • Рядок 2: відображається, коли параметр вимкнено
  • Рядок 3: відображається, коли параметр вимкнено

Отже, коли параметр увімкнено, таблиця повідомляє про два рядки, які є:

  • Рядок 0: Варіант із перемикачем ON / OFF
  • Рядок 1: відображається, коли параметр увімкнено

Якщо параметр ВИМКНЕНО, таблиця повідомляє про чотири рядки:

  • Рядок 0: Варіант із перемикачем ON / OFF
  • Рядок 1: відображається, коли параметр увімкнено
  • Рядок 2: відображається, коли параметр вимкнено
  • Рядок 3: відображається, коли параметр вимкнено

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

  • Неправильно сказати таблиці, що кількість рядків відрізняється від того, що імовірно міститься в базових даних.

  • Я, здається, не можу оживити зміни. Я спробував використовувати tableView: reloadSections: withRowAnimation: замість reloadData і результати, здається, не мають сенсу, я все ще намагаюся налагодити це. Наразі, що здається, що tableView не оновлює правильні рядки, тому одна залишається прихованою, яку слід відобразити, а під першим рядком залишається порожнеча Я думаю, це може бути пов’язане з першим моментом про основні дані.

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


Я впевнений, що вам слід зателефонувати ще [[self tableView] reloadData];один раз, сховавши клітини
Шмідт

Вибачте, що відроджуєте це, але як вам вдалося підкласи UITableViewController і використовувати його зі статичними осередками? Xcode мені не дозволить.
Дані Джумаа

Незалежно від вас, вам не потрібно підкласи UITableView. У дошці розкадру виберіть TableViewController, а потім натисніть на TableView. Тепер ви можете вибрати між динамічними / статичними осередками.
Шмідт

1
Я знайшов рішення, як анімувати статичні комірки ховати / показувати. Просто зателефонуйте return [super tableView:tableView cellForRowAtIndexPath:indexPath];в UITableViewControllerпідкласі для створення статичних осередків.
Шлях до

8

Відповідно до відповіді Юстаса, але для Swift 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = super.tableView(tableView, cellForRowAt: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAt: indexPath)
}

1
вам може знадобитися a tableView.reloadRows(at:, with:)для оновлення комірок, якщо ви змінюєте висоту, поки рядок уже видно.
Мороз-Лі

5

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

  1. створити IBOutlet для контролера перегляду. @IBOutlet weak var myCell: UITableViewCell!

  2. Оновіть myCellу своїй спеціальній функції, наприклад, ви можете додати її у viewDidLoad:

override func viewDidLoad() { super.viewDidLoad() self.myCell.isHidden = true }

  1. у вашому методі делегата:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) guard !cell.isHidden else { return 0 } return super.tableView(tableView, heightForRowAt: indexPath) }

Це зменшить вашу логіку в методі делегування, і вам потрібно лише зосередитися на ваших бізнес-вимогах.


4

Наведені вище відповіді, які приховують / показують комірки, змінюють rowHeight або псують з обмеженнями автоматичного макета, не працювали для мене через проблеми з автоматичним компонуванням. Код став нестерпним.

Для простої статичної таблиці найкраще працювало:

  1. Створіть розетку для кожної комірки в статичній таблиці
  2. Створіть масив лише з розетки комірок для показу
  3. Перезазначити cellForRowAtIndexPath, щоб повернути комірку з масиву
  4. Замініть номерOfRowsInSection, щоб повернути кількість масиву
  5. Реалізуйте метод, щоб визначити, які клітинки повинні бути у цьому масиві, і викликайте цей метод, коли це потрібно, а потім reloadData.

Ось приклад з мого контролера подання таблиці:

@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!

var cellsToShow: [UITableViewCell] = []

override func viewDidLoad() {
    super.viewDidLoad()
    determinCellsToShow()
}

func determinCellsToShow() {
    if detail!.duration.type != nil {
        cellsToShow = [titleCell, nagCell, categoryCell]
    }
    else {
        cellsToShow = [titleCell,  categoryCell]
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return cellsToShow[indexPath.row]
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return cellsToShow.count
}

Це спрацювало чудово навіть через 5 років! Дуже дякую.
Шроквелл

2020 рік, і це найбільше рішення для цього. Ніякого злому не потрібно.
мдонаті

3

Простий метод сумісності iOS 11 та IB / Розкладки

Для iOS 11 я виявив, що модифікована версія відповіді Мохамеда Салеха найкраще працює з деякими вдосконаленнями на основі документації Apple. Це добре анімує, уникає некрасивих хакерів або твердо кодованих значень і використовує висоти рядків, вже встановлені в Interface Builder .

Основна концепція - встановити висоту рядка на 0 для будь-яких прихованих рядків. Потім використовуйте tableView.performBatchUpdatesдля запуску анімації, яка працює стабільно.

Встановити висоту комірок

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath == indexPathOfHiddenCell {
        if cellIsHidden {
            return 0
        }
    }
    // Calling super will use the height set in your storyboard, avoiding hardcoded values
    return super.tableView(tableView, heightForRowAt: indexPath)
}

Ви хочете, щоб переконатися, cellIsHiddenі indexPathOfHiddenCellвони встановлені відповідно до вашої справи використання. Для мого коду вони є властивостями в моєму контролері подання таблиці.

Включення клітини

За допомогою будь-якого способу контролю видимості (швидше за все, дії кнопки чи didSelectRow), перемикайте стан cellIsHidden всередині performBatchUpdatesблоку:

tableView.performBatchUpdates({
                // Use self to capture for block
                self.cellIsHidden = !self.cellIsHidden 
            }, completion: nil)

Apple рекомендує performBatchUpdatesбільше beginUpdates/endUpdates коли це можливо.


1

Я знайшов рішення для оживлених прихованих комірок у статичній таблиці.

// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
    BlockExecutor * executor = [[BlockExecutor alloc] init];
    executor.block = block;
    return executor;
}
@end

Потрібен лише один додатковий словник:

@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end

І подивіться на реалізацію MyTableViewController. Нам потрібні два методи для перетворення indexPath між видимими і невидимими індексами ...

- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row <= indexPath.row + rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}

- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row < indexPath.row - rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}

Зміна значення однієї IBA на UISwitch:

- (IBAction)birthdaySwitchChanged:(id)sender
{
    NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
    if (self.birthdaySwitch.on)
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    else
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

Деякі методи UITableViewDataSource та UITableViewDelegate:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
    for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
        if (indexPath.section == section)
        {
            BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
            numberOfRows -= (executor.block()?0:1);
        }
    return numberOfRows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // initializing dictionary
    self.hidableCellsDict = [NSMutableDictionary dictionary];
    [self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}

- (void)viewDidUnload
{
    [self setBirthdaySwitch:nil];
    [super viewDidUnload];
}

@end

1

Відповідь швидко :

Додайте такий спосіб у свій TableViewController:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

якщо tableView намагається намалювати клітинку, яку ви хочете приховати, вона не відображатиме її, оскільки її висота буде встановлена ​​на 0pt завдяки вищевказаному методу, все інше залишається незмінним.

Зверніть увагу, що indexPathOfCellYouWantToHideможна змінити будь-коли :)


1

В> Швидкий 2.2, тут я поєднав кілька відповідей.

Зробіть розетку з рекламної плати, щоб зв’язатись із staticCell.

@IBOutlet weak var updateStaticCell: UITableViewCell!

override func viewDidLoad() {
    ...
    updateStaticCell.hidden = true
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if indexPath.row == 0 {
        return 0
    } else {
        return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
}

Я хочу приховати свою першу комірку, щоб я встановив висоту 0, як описано вище.


1

Швидкий 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    var height = super.tableView(tableView, heightForRowAt: indexPath)
    if (indexPath.row == HIDDENROW) {
        height = 0.0
    }
    return height
}

0

Для найпростішого сценарію, коли ви ховаєте комірки в самій нижній частині таблиці, ви можете скорегувати contentView contentVset після того, як приховати комірок:

- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
    CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}


0

Рішення від k06a ( https://github.com/k06a/ABStaticTableViewController ) краще, оскільки воно приховує цілий розділ, включаючи заголовки та колонтитули комірок, де це рішення ( https://github.com/peterpaulis/StaticDataTableViewController ) приховує все, крім колонтитулу.

EDIT

Щойно я знайшов рішення, якщо ви хочете приховати колонтитул StaticDataTableViewController. Це те, що потрібно скопіювати у файл StaticTableViewController.m:

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
    if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
        return nil;
    } else {
        return [super tableView:tableView titleForFooterInSection:section];
    }
}

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

    CGFloat height = [super tableView:tableView heightForFooterInSection:section];

    if (self.originalTable == nil) {
        return height;
    }

    if (!self.hideSectionsWithHiddenRows) {
        return height;
    }

    OriginalSection * os = self.originalTable.sections[section];
    if ([os numberOfVissibleRows] == 0) {
       //return 0;
        return CGFLOAT_MIN;
    } else {
        return height;
    }

    //return 0;
    return CGFLOAT_MIN;
}

0

Звичайно, ви можете. По-перше, поверніться до таблиці tableView кількість комірок, які ви хочете показати, а потім зателефонуйте, superщоб досягти певної комірки з вашої табло та повернути її для tableView:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.mode.numberOfCells()
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))

    return cell
}

Якщо ваші клітини мають різну захищеність, поверніть її також:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}

0

Окрім рішення @Saleh Masum:

Якщо ви отримаєте помилки автоматичного розміщення , ви можете просто усунути обмеження зtableViewCell.contentView

Швидкий 3:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)

    if tableViewCell.isHidden == true
    {
        tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
        return 0
    }
    else{
        return super.tableView(tableView, heightForRowAt: indexPath)
    }

}

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


0

У мене є кращий спосіб динамічно приховати статичні комірки та навіть секції без будь-яких злому.

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

Мій підхід полягає у створенні масиву секцій статичних комірок. Тоді вміст подання таблиці буде керуватися масивом розділів.

Ось приклад коду:

var tableSections = [[UITableViewCell]]()

private func configTableSections() {
    // seciton A
    tableSections.append([self.cell1InSectionA, self.cell2InSectionA])

    // section B
    if shouldShowSectionB {
        tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
    }

    // section C
    if shouldShowCell1InSectionC {
        tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
    } else {
        tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
    }
}

func numberOfSections(in tableView: UITableView) -> Int {
    return tableSections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tableSections[section].count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    return tableSections[indexPath.section][indexPath.row]
}

Таким чином, ви можете скласти весь свій конфігураційний код разом, не записуючи неприємний код, щоб обчислити кількість рядків і розділів. І звичайно, ні0 висоти.

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

Аналогічно, ви можете створити масив заголовка розділу та масив заголовків колонтитулу розділу, щоб динамічно конфігурувати заголовки розділу.

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