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

UITableView Не соблюдает heightForHeaderInSection/heightForFooterInSection?

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

У меня проблема с заголовком и нижним колонтитулом для разделов, которые отображаются, даже если нет строки, и, несмотря на то, что я переопределил метод делегата для возврата 0.0f.

Вот как это выглядит - вы можете увидеть ~ 20p серого пространства вверху, верхние и нижние колонтитулы по 10p каждый для раздела с 0 строками.

alt text
(источник: hanchorllc.com)

Вот мой псевдокод:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
     if ([section hasRow]) {
          return 10.0f;
     } else {
          return 0.0f;
     }
}



- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
     if ([section hasRow]) {
          return 10.0f;
     } else {
          return 0.0f;
     }
}

Я проверил, что эти методы вызываются и что происходит правильный путь выполнения.

Один недостаток - этот контроллер представления использует XIB и что UITableView имеет значения заголовка раздела и нижнего колонтитула, установленные на 10,0 (по умолчанию), хотя я думал, что он был переопределен методом делегата, если он реализован.

Это приложение предназначено для 3.0.

Что я делаю неправильно?

4b9b3361

Ответ 1

В "сгруппированном" UITableView на iPhone он будет по-прежнему показывать минимальную высоту для верхнего и нижнего колонтитула, эффективно игнорируя ваш код, чтобы установить его на ноль. Он не связан с положением XIB.

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

Я боюсь всего этого, потому что вы ошибетесь в том, чтобы очистить размер заголовка, когда нет строк данных; вместо этого вы не должны вызывать какие-либо методы для пустых разделов. Это плохой метод, потому что, по сути, iPhone должен вызывать больше методов, чем следовало бы, а также отображать больше заголовков, чем вы хотите (обычно - иногда люди хотят оставить пустые заголовки там, например, для перетаскивания).

Итак, допустим, предположим, что у вас есть несколько разделов, но только некоторые из них имеют более одной строки (возможно, на основе пользовательских настроек/фильтров).

неправильный способ реализации:

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

а затем для каждого раздела у вас нет результата для:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  if (![section hasRow]) return 0;
}

и

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
  if (![section hasRow]) return 0.0f;
}

правильный способ реализации:

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

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

Надеюсь, что это поможет!

Ответ 2

Это немного сложно, так как значение 0.0f не принимается. но все, что достаточно близко к нулю, сделает трюк. Если вы решите не быть идеальным пикселем и хотите круглые числа, то 1.0f будет делать почти то же самое, что разница в высоте 1px будет довольно заметной.

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if(section == 1 )
        return 0.000001f;
    else return 44.0f; // put 22 in case of plain one..
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return 0.000001f; //removing section footers
}

Ответ 3

Похоже, что таблица относится к tableView:heightForHeaderInSection:, только если tableView:viewForHeaderInSection: не nil, или если tableView:titleForHeaderInSection: не nil или @"". То же самое верно для высот нижнего колонтитула.

Предположим, что у вас нет заголовков заголовков или заголовков, просто добавьте это в свой делегат таблицы:

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
  return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
}

Ответ 4

У меня была аналогичная проблема:  Я загрузил UITableView из XIB (то же самое, что и вы), и предоставил высоту 0 для некоторых нижних колонтитулов раздела с tableView:heightForFooterInSection (то же самое, что и вы), но значение было проигнорировано.

Исправление было простым: также установите высоту нижнего колонтитула 0.0 в XIB. (В построителе интерфейса выберите "Вид таблицы", нажмите "Command-3", чтобы просмотреть "Инспектор размеров", найдите поле высоты нижнего колонтитула вверху)

Как только это было сделано, он выполнил высоту пользовательского нижнего колонтитула, как ожидалось. (Может быть, он обрабатывает высоту нижнего колонтитула XIB как минимум?)

Ответ 5

Я обнаружил, что в моем случае нужно было 2 вещи, чтобы убить нижний колонтитул phantom:

1), установив представление таблицы sectionFooterHeight на 0, то есть в viewDidLoad добавив:

tableView.sectionFooterHeight = 0

2) добавление метода делегата:

override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
    return UIView(frame: CGRect.zero)
}

(с использованием Swift 2.2)

Ответ 6

Это работает для меня:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    tableView.sectionHeaderHeight = (section == 0 ? 10 : 0);
    return tableView.sectionHeaderHeight;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    tableView.sectionFooterHeight = (section == 0 ? 20 : 4);
    return tableView.sectionFooterHeight;
}

Ответ 7

Собственно, со мной это происходит наоборот. Я назначил заголовок раздела равным 10 в xib, но для первого раздела я хочу заголовок заголовка размера. Я использую этот метод в своем UITableViewCotroller

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.section==0)
        return 125;
    return tableView.rowHeight;
}

Но высота заголовка раздела не изменяется, даже если метод вызван.

Ответ 8

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

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

Предположим, что мой первый раздел - это контактные данные с именем, фамилией и возрастом. Я определю этот раздел с идентификатором "1" (хотя технически, как я объясню позже, это может быть любое число). Теперь, если мой метод определяет, что этот раздел должен быть видимым, я нажимаю значение '1' на массив.

Следующий раздел, который я хочу показать, - это адрес и может содержать 3-4 строки/ячейки. Как и выше, логика в моем методе определяет, должен ли адрес быть видимым, нажимая "2" на массив.

Теперь....если мы хотели, чтобы обе секции были видны, у нас был бы массив с длиной 2 и двумя элементами [1,2]. Если бы мы только хотели, чтобы информация о контакте была видимой, наш массив имел бы длину 1 с элементами [1] и [2] только для адреса.

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

наш оператор switch теперь будет выглядеть примерно так:

switch(ourArray[indexPath.section]){
    case 1:
        <Return the number of rows for the contact details which we said would be 3>
        break;
    case 2:
        <Return the number of rows for the address details which we said would be 4>
        break;
    case 3:
        <Return another number for some section that is referenced by the id '3'>
        break; 
}

Заметьте, что я положил случай 3 в мой переключатель. Поскольку массив в нашем примере содержит только значения "1" и "2", случай 3 никогда не будет сопоставляться и поэтому игнорируется, если мы не решили добавить/включить этот случай, нажав его на массив.

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

Я использую вышеупомянутое религиозно, так как это позволяет мне отделить индексирование и построение разделов.

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

Ответ 9

Я использую следующее решение:

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return section == 0 ? CGFloat.leastNormalMagnitude : 8
}

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return 0
}

Результат:

result