Разрешить представление заголовка только для определенных разделов с помощью iOS UICollectionView

В приведенном ниже коде мой заголовок отображается правильно, но для каждого из разделов в UICollectionView:

-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
          viewForSupplementaryElementOfKind:(NSString *)kind
                                atIndexPath:(NSIndexPath *)indexPath {
    UICollectionReusableView * headerView =
        [collectionView 
            dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader 
                               withReuseIdentifier:@"SectionHeaderCollectionReusableView"
                                      forIndexPath:indexPath];
    switch (indexPath.section) {
        case Section_One:
            return headerView;
        case Section_Two:
            return headerView;
        case Section_Three:
            return headerView;
        case Section_Four:
            return headerView;
        case Section_Five:
            return headerView;

        default:
            return headerView;
    }
}

Вместо этого я бы хотел не отображать представление заголовка для «Section_One» или «Section_Two», а возвращение «nil» приводит к «NSInternalInconsistencyException»:

-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
          viewForSupplementaryElementOfKind:(NSString *)kind
                                atIndexPath:(NSIndexPath *)indexPath {
    UICollectionReusableView * headerView =
        [collectionView 
            dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader 
                               withReuseIdentifier:@"SectionHeaderCollectionReusableView"
                                      forIndexPath:indexPath];
    switch (indexPath.section) {
        case Section_One:
            return nil;
        case Section_Two:
            return nil;
        case Section_Three:
            return headerView;
        case Section_Four:
            return headerView;
        case Section_Five:
            return headerView;

        default:
            return nil;
    }
}

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


person Gifreakius    schedule 28.05.2014    source источник
comment
Какие еще детали предлагаются с NSInternalInconsistencyException?   -  person nhgrif    schedule 28.05.2014
comment
*** Завершение работы приложения из-за неперехваченного исключения «NSInternalInconsistencyException», причина: «представление, возвращенное из -collectionView: viewForSupplementaryElementOfKind: atIndexPath (UICollectionElementKindSectionHeader,‹ NSIndexPath: 0xc000000000000016 ›‹ NSIndexPath: 0xc000000000000016 ›‹ NSIndexPath: 0xc000000000000016 ›‹ - = 2, путь не был получен до вызов -dequeueReusableSupplementaryViewOfKind: withReuseIdentifier: forIndexPath: or is nil ((null)) '   -  person Gifreakius    schedule 28.05.2014


Ответы (5)


Идите вперед и верните заголовок для каждого раздела, а затем установите размер заголовка раздела равным нулю в этой функции UICollectionViewDelegate.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return CGSizeZero;
    }else {
        return CGSizeMake(self.collectionView.bounds.size.width, desiredHeight);
    }
}
person mwright    schedule 28.05.2014
comment
Что, если один и тот же контроллер обрабатывает два представления коллекции, а вам не нужны заголовки и разделы в другом представлении коллекции? Кажется плохой практикой просто возвращать какой-то заголовок для обоих представлений? - person Markus Rautopuro; 19.02.2016
comment
(Я добавил ответ по этому поводу ниже.) - person Markus Rautopuro; 19.02.2016
comment
@MarkusRautopuro Это конкретный вариант использования, который, вероятно, должен быть рассмотрен в отдельном вопросе. - person mwright; 25.10.2016
comment
Почему, Apple, почему? - person Tamás Sengel; 14.06.2017
comment
Комментарий трехлетней давности ... обратите внимание, что вы можете получить эталонный размер, если ваш макет UICollectionViewFlowLayout, таким образом вы можете делегировать желаемый размер в Storyboard и сделать свой код более совместимым с MVC: return [(UICollectionViewFlowLayout *)collectionViewLayout headerReferenceSize]; - person Alejandro Iván; 25.09.2017

У меня был случай, когда один UICollectionViewController управлял двумя UICollectionView (упоминаемыми позже как представления коллекции 1 и 2), и мне нужны были заголовки для первого и никаких заголовков (или нижних колонтитулов) для второго.

Чего не хватает в ответе @mwright, так это того, что когда вы возвращаете CGSizeZero для представления коллекции 2 следующим образом:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    if collectionView == self.collectionView2 {
        return CGSizeZero
    }
    return < something else >
}

... означает, что collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView вообще не вызывается для представления коллекции 2.

Это означает, что вам не нужно напрасно беспокоиться о возврате «неправильного» заголовка для второго представления коллекции.

person Markus Rautopuro    schedule 19.02.2016

Я заметил, что принятый ответ не работает, когда вы использовали AutoLayout в XIB для многоразового заголовка.

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

Хотя это само по себе не является технически катастрофой, все же это грязно. А в эпоху Swift и AutoLayout должно быть более чистое решение. Кроме того, вы никогда не захотите отправлять такие вещи клиенту, когда вы на работе.

Чтобы исправить это, вместо того, чтобы просто вызывать referenceSizeForHeaderInSection: и возвращать CGSizeZero, я создал другой подкласс UICollectionReusableView с XIB и установил высоту представления внутри него на 0.

Позже я удаляю этот вариант из очереди за пределами моего оператора switch, содержащегося в методе viewForSupplementaryElementOfKind. Это удовлетворяет как , так и визуальные требования Interface Builder! ????

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

person topLayoutGuide    schedule 17.06.2016
comment
это для конкретного случая, когда вы предоставляете представление заголовка, отличное от значения по умолчанию, и, вероятно, его лучше обработать в отдельном вопросе - person mwright; 25.10.2016
comment
На самом деле @mwright это полезный ответ, и он должен оставаться на этом вопросе. Спасибо кокотч - person Clay Ellis; 29.10.2016
comment
Вы неправильно поняли, я не сказал, что это бесполезно, я сказал, что это не имеет прямого отношения к заданному вопросу. Спрашивающий не указал, что они использовали настраиваемый заголовок с автоматическим размещением, и в этом случае это был бы правильный ответ. - person mwright; 01.11.2016

**

Если вы вернете значение размера (0, 0), заголовок не будет добавлен.

**

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {

 switch section {
 case 0:
   return CGSize(width: collectionView.bounds.width, height: 70)
 case 1:
   return CGSize(width: 0, height: 0) // NO HEADER WILL BE ADDED
 case 2:
   return CGSize(width: collectionView.bounds.width, height: 70)
 case 3:
   return CGSize(width: 0, height: 0) // NO HEADER WILL BE ADDED
 default:
   return CGSize(width: collectionView.bounds.width, height: 70)
 }

}
person kamalraj venkatesan    schedule 01.07.2018

Попробуйте вернуть пустой вид. Возможно, лучший способ, но это может сработать ....

person Robert Smith    schedule 28.05.2014
comment
return [UICollectionReusableView новый]; приводит к тому же исключению, к сожалению. Есть ли другой способ вернуть пустой вид? - person Gifreakius; 28.05.2014
comment
UIView * eView = [UIView alloc] initWithFrame: CGRectMake (0,0,0,0)]; - person Robert Smith; 28.05.2014
comment
Вам нужно будет сделать его свойством, чтобы использовать его в делегате / источнике данных представления коллекции. - person Robert Smith; 28.05.2014
comment
Создание экземпляра представления таким образом как локальной переменной в «viewForSupplementaryElementOfKind» приводит к тому же исключению. Добавление свойства и его назначение также вызывает исключение (независимо от того, создается ли его экземпляр в методе или в viewDidLoad). - person Gifreakius; 28.05.2014