CollectionView: viewForSupplementaryElementOfKind: atIndexPath: вызов только с помощью UICollectionElementKindSectionHeader

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

У меня есть свои собственные подклассы UICollectionReusableView, и я регистрирую их как для заголовка, так и для нижнего колонтитула в методе viewDidLoad моего контроллера представления.

Я реализовал метод collectionView:viewForSupplementaryElementOfKind:atIndexPath:, но для каждого раздела он вызывается только с kind UICollectionElementKindSectionHeader. Поэтому мой нижний колонтитул даже не создан.

Любые идеи, почему это происходит?

Ответ 1

Кажется, что я должен установить footerReferenceSize для макета представления коллекции. Странно, что мне не нужно было делать это с заголовком.

Ответ 2

Я нашел код, возможно, может помочь вам

- ( UICollectionReusableView * ) collectionView : ( UICollectionView * ) collectionView viewForSupplementaryElementOfKind : ( NSString * ) kind atIndexPath : ( NSIndexPath * ) indexPath
{
    UICollectionReusableView * reusableview = nil ;

    if ( kind == UICollectionElementKindSectionHeader )
    {
        RecipeCollectionHeaderView * headerView = [ collectionView dequeueReusableSupplementaryViewOfKind : UICollectionElementKindSectionHeader withReuseIdentifier : @ "HeaderView" forIndexPath : indexPath ] ;
        NSString * title = [ [ NSString alloc ] initWithFormat : @ "Recipe Group #%i" , indexPath.section + 1 ] ;
        headerView.title.text = title;
        UIImage * headerImage = [ UIImage imageNamed : @ "header_banner.png" ] ;
        headerView.backgroundImage.image = headerImage;

        reusableview = headerView;
    }
    if ( kind == UICollectionElementKindSectionFooter )
    {
        UICollectionReusableView * footerview = [ collectionView dequeueReusableSupplementaryViewOfKind : UICollectionElementKindSectionFooter withReuseIdentifier : @ "FooterView" forIndexPath : indexPath ] ;

        reusableview = footerview;
    }

    return reusableview;
}

Ответ 3

(с использованием Swift 3.1, Xcode 8.3.3)
Первый, класс заголовка записи или nib

collectionView.register(ShortVideoListHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header")

Второй, установите headerReferenceSize; альтернативно, вы можете вернуть headerReferenceSize в делегат коллекцииView

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.headerReferenceSize = CGSize(width: view.bounds.width, height: 156)
}

Третий, напишите свой собственный класс заголовков, например

class ShortVideoListHeader: UICollectionReusableView {
    let titleLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        addSubview(titleLabel)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        titleLabel.sizeToFit()
        titleLabel.frame.origin = CGPoint(x: 15, y: 64 + (frame.height - 64 - titleLabel.frame.height) / 2) // navigationBar height is 64
    }
}

Четвертый, верните свой экземпляр заголовка в методы dataView источника collectionView,

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    switch kind {
    case UICollectionElementKindSectionHeader:
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header", for: indexPath) as! ShortVideoListHeader
        header.titleLabel.text = title
        header.setNeedsLayout()
        return header

    default:
        return UICollectionReusableView()
    }
}

Кстати, Apple Document отвечает, как скрыть заголовок раздела.

Этот метод должен всегда возвращать действительный объект вида. Если вам не нужен дополнительный просмотр в конкретном случае, ваш объект макета не должен создавать атрибуты для этого представления. Кроме того, вы можете скрыть представления, установив скрытый  свойство соответствующих атрибутов YES или установить альфа  свойство атрибутов равно 0. Чтобы скрыть представления заголовка и нижнего колонтитула в макете потока, вы также можете установить ширину и высоту этих представлений на 0.