UITableView установлен на статические ячейки.Можно ли скрыть некоторые ячейки программно? - PullRequest
126 голосов
/ 24 ноября 2011

UITableView установлен на статические ячейки.

Можно ли программно скрыть некоторые ячейки?

Ответы [ 22 ]

160 голосов
/ 12 июня 2013

Чтобы скрыть статические ячейки в UITable:

  1. Добавьте этот метод :

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

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

Swift:

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. Мы определяем целевую ячейку, создавая для нее выход:

В конструкторе создайте выход для ячейки, которую вы хотите скрыть. Выход для одной такой ячейки выше называется "cellYouWantToHide". Проверка«Клип подпредставлений» в IB для ячеек, которые вы хотите скрыть. Скрытые ячейки должны иметь ClipToBounds = YES.В противном случае текст будет накапливаться в UITableView.
48 голосов
/ 31 января 2013

Вы ищете это решение:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

, которое может показать / скрыть / перезагрузить любую статическую ячейку (s) с анимацией или без нее!

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

Обратите внимание, что всегда следует использовать только (reloadDataAnimated: YES / NO) (не вызывайте [self.tableView reloadData] напрямую)

Это нене используйте хакерское решение с установкой высоты 0 и позволяет анимировать изменения и скрывать целые секции

36 голосов
/ 09 октября 2013

Лучший способ, как описано в следующем блоге http://ali -reynolds.com / 2013/06/29 / скрыть-клетка-в-статическому таблицы ракурса /

Создайте свой статический вид таблицы как обычно в конструкторе интерфейсов - в комплекте со всеми потенциально скрытыми клетками. Но есть одна вещь, которую вы необходимо сделать для каждой потенциальной ячейки, которую вы хотите скрыть - проверьте Свойство «Clip subviews» ячейки, в противном случае содержимое ячейка не исчезает, когда вы пытаетесь скрыть ее (уменьшив высота - позже).

ТАК - у вас есть переключатель в ячейке, и переключатель должен скрывать и показать несколько статических ячеек. Подключите его к 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;
}

И это все. Нажмите на переключатель, и ячейка скрывается и появляется снова с хорошая, плавная анимация.

34 голосов
/ 24 февраля 2012

Мое решение идет в том же направлении, что и Гарет, хотя я делаю некоторые вещи по-другому.

Вот так:

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

Если ваша таблица имеет несколько разделов или ячейки имеют разную высоту, вам нужно переопределить больше методов. Здесь применяется тот же принцип: перед делегированием в super необходимо сместить indexPath, section и row.

Также следует помнить, что параметр 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];
}
13 голосов
/ 04 августа 2016
  1. В конструкторе создайте розетку для ячеек, которые вы хотите скрыть. Например, вы хотите скрыть 'cellOne', поэтому в viewDidLoad () сделайте это

cellOneOutlet.hidden = true

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

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

}
11 голосов
/ 14 марта 2012

Я предложил альтернативу, которая фактически скрывает разделы и не удаляет их. Я попробовал подход @ 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];
}

Затем, если у вас есть определенные строки, которые нужно скрыть, вы можете настроить numberOfRowsInSection и какие строки будут возвращены в 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, потому что границы не будут отображаться правильно.

10 голосов
/ 04 июля 2015

Оказывается, вы можете скрывать и показывать ячейки в статическом UITableView - и с анимацией. И это не так сложно сделать.

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

Демонстрационное видео проекта

Суть:

  1. Use tableView:heightForRowAtIndexPath: для динамического определения высоты ячеек на основе некоторого состояния.
  2. Когда состояние изменяет отображение / скрытие ячеек, вызывая tableView.beginUpdates();tableView.endUpdates()
  3. Не звоните tableView.cellForRowAtIndexPath: внутрь tableView:heightForRowAtIndexPath:. Используйте кэшированные indexPaths для дифференциации ячеек.
  4. Не прячьте клетки. Установите вместо этого свойство «Clip Subviews» в Xcode.
  5. Используйте пользовательские ячейки (не простые и т. Д.), Чтобы получить приятную скрытую анимацию. Также правильно обрабатывайте Auto Layout для случая, когда высота ячейки == 0.

Подробнее в моем блоге (русский язык)

8 голосов
/ 29 ноября 2011

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

Я скрываю строки, основываясь на состоянии переключателя ВКЛ / ВЫКЛ в первой строке первого раздела.Если переключатель включен, под ним находится 1 строка в том же разделе, в противном случае есть 2 разные строки.

У меня есть селектор, вызываемый при переключении переключателя, и я устанавливаю переменную, чтобы указать, какое состояние IЯ нахожусь в. Затем я вызываю:

[[self tableView] reloadData];

Я переопределяю функцию tableView: willDisplayCell: forRowAtIndexPath: , и если ячейка должна быть скрыта, я делаю это:

[cell setHidden:YES];

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

Чтобы удалить пробел, переопределите функцию tableView: heightForRowAtIndexPath: и верните 0 для строк, которые должны быть скрыты.

Вам также необходимо переопределить tableView: numberOfRowsInSection: и вернуть количество строк в этом разделе.Здесь нужно сделать что-то странное, чтобы, если ваш стол был сгруппированным, закругленные углы появлялись в правильных ячейках.В моей статической таблице есть полный набор ячеек для раздела, поэтому есть первая ячейка, содержащая параметр, затем 1 ячейка для параметров состояния ON и еще 2 ячейки для параметров состояния OFF, всего 4 ячейки.Когда опция включена, я должен вернуть 4, это включает скрытую опцию, так что последняя отображаемая опция имеет закругленную рамку.Когда опция отключена, последние две опции не отображаются, поэтому я возвращаю 2. Это все кажется неуклюжим.Извините, если это не очень понятно, это сложно описать.Просто чтобы проиллюстрировать настройку, приведем конструкцию секции таблицы в IB:

  • Строка 0: опция с переключателем ВКЛ / ВЫКЛ
  • Строка 1: отображается при включенной опции
  • Строка 2: отображается при выключенной опции
  • Строка 3: отображается при выключенной опции

Таким образом, когда опция включена, таблица отображает две строки:

  • Строка 0: опция с переключателем ВКЛ / ВЫКЛ
  • Строка 1: отображается при включенной опции

Когда опция выключена, таблица отображает четыреряды:

  • Строка 0: опция с переключателем ВКЛ / ВЫКЛ
  • Строка 1: отображается при включенной опции
  • Строка 2: отображается при выключенной опции
  • Строка 3: отображается, когда опция выключена

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

  • Неправильно говорить таблице, что число строк отличается от того, которое предположительно содержится в базовых данных.

  • Я не могу оживить изменения.Я попытался использовать tableView: reloadSections: withRowAnimation: вместо reloadData, и результаты, кажется, не имеют смысла, я все еще пытаюсь заставить это работать.В настоящее время, по-видимому, происходит то, что tableView не обновляет правильные строки, поэтому одна остается скрытой, которая должна отображаться, и под первой строкой остается пустота.Я думаю, что это может быть связано с первым пунктом о базовых данных.

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

7 голосов
/ 17 апреля 2018

Согласно ответу Юстаса, но для Свифта 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)
}
3 голосов
/ 13 июня 2015

Приведенные выше ответы, которые скрывают / показывают ячейки, изменяют rowHeight или связываются с ограничениями автоматической разметки, не работают для меня из-за проблем с автоматической разметкой. Код стал невыносим.

Для простой статической таблицы для меня лучше всего было:

  1. Создать выход для каждой ячейки в статической таблице
  2. Создать массив только с точками выхода ячеек
  3. Переопределить cellForRowAtIndexPath, чтобы вернуть ячейку из массива
  4. Переопределить numberOfRowsInSection для возврата счетчика массива
  5. Реализуйте метод, чтобы определить, какие ячейки должны быть в этом массиве, и при необходимости вызывайте этот метод, а затем перезагружайте данные.

Вот пример из моего контроллера табличного представления:

@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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...