Заголовки разделов в UICollectionView отображаются только первым

#swift #uicollectionview #uicollectionviewflowlayout

#быстрый #uicollectionview #uicollectionviewflowlayout

Вопрос:

Я создал класс для заголовка раздела и загружаю его в свой UICollectionView. Я могу отобразить первый заголовок (хотя и странно, см. Ниже), однако все следующие заголовки разделов пусты. На размер ссылаются, однако содержимое (цвет фона, метка) отображаться не будет.

А затем также … заголовок одного раздела, который отображается, отображается с отступом ок. 150 пикселей без видимой причины. Выровнены ли заголовки по центру по умолчанию? Если да, то как бы я выровнял их по левому краю?

Мой класс заголовка раздела:

 func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    switch kind {
    case UICollectionView.elementKindSectionHeader:
        let section = indexPath.section
        switch section {
        case 0:
            let tagsHeader = searchCollectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "TagsHeaderView", for: indexPath) as! SectionHeaderView
            tagsHeader.headerString = "Recent Tags"
            tagsHeader.backgroundColor = .green
            return tagsHeader
        default:
            let tagsHeader = searchCollectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "TypeHeaderView", for: indexPath) as! SectionHeaderView
            tagsHeader.headerString = "Type"
            tagsHeader.backgroundColor = .blue
            return tagsHeader
        }
    default:
        return UICollectionReusableView()
    }
}
 

В моем UICollectionView

 func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    switch kind {
    case UICollectionView.elementKindSectionHeader:
        let section = indexPath.section
        switch section {
        case 0:
            let tagsHeader = searchCollectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "TagsHeaderView", for: indexPath) as! SectionHeaderView
            tagsHeader.headerString = "Recent Tags"
            tagsHeader.backgroundColor = .green
            return tagsHeader
        default:
            let tagsHeader = searchCollectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "TypesHeaderView", for: indexPath) as! SectionHeaderView
            tagsHeader.headerString = "Type"
            tagsHeader.backgroundColor = .blue
            return tagsHeader
        }
    default:
        return UICollectionReusableView()
    }
}


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    if section == 0 {
        return CGSize(width: view.frame.width, height: 18   22   6)
    } else {
        return CGSize(width: view.frame.width, height: 100)
    }
}
 

Вот как я создаю экземпляр своего UICollectionView

 let searchCollectionView: UICollectionView = {
    let layout = LeftAlignedCollectionViewFlowLayout()
    layout.minimumInteritemSpacing = 6
    layout.minimumLineSpacing = 6
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.isScrollEnabled = false
    cv.register(TokenCell.self, forCellWithReuseIdentifier: "TokenCell")
    cv.register(SectionHeaderView.self, forSupplementaryViewOfKind:UICollectionView.elementKindSectionHeader, withReuseIdentifier: "TagsHeaderView")
    cv.register(SectionHeaderView.self, forSupplementaryViewOfKind:UICollectionView.elementKindSectionHeader, withReuseIdentifier: "TypesHeaderView")
    cv.backgroundColor = .white
    cv.showsVerticalScrollIndicator = false
    cv.alwaysBounceVertical = false
    cv.translatesAutoresizingMaskIntoConstraints = false
    return cv
}()
 

Моя коллекция viewflowlayout

 class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributes = super.layoutAttributesForElements(in: rect)

    var leftMargin = sectionInset.left
    var maxY: CGFloat = -1.0
    attributes?.forEach { layoutAttribute in
        if layoutAttribute.frame.origin.y >= maxY {
            leftMargin = sectionInset.left
        }

        layoutAttribute.frame.origin.x = leftMargin

        leftMargin  = layoutAttribute.frame.width   minimumInteritemSpacing
        maxY = max(layoutAttribute.frame.maxY , maxY)
    }

    return attributes
}
 

}

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

Комментарии:

1. Вы уверены, что хотите переключить раздел, а не строку? Обычно существует только один раздел, содержащий несколько строк. Проблема, вероятно, заключается в том, что у вас есть только один раздел, поэтому значение по умолчанию никогда не вызывается. Попробуйте изменить везде, где вы используете слово «раздел» на «строка»

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

3. Однако вы правы в той части, что мой случай по умолчанию не срабатывает. Установив там точку останова, она никогда не будет достигнута. Попытка установить для этого случая значение section == 1 тоже не работает. Разве не так я мог бы добраться до своего раздела или разместить отдельные заголовки в каждом разделе?

Ответ №1:

У меня возникла та же проблема при создании моего тега view. Проблема в вашем CollectionViewFlowLayout .

let attributes = super.layoutAttributesForElements(in: rect)

Эта строка получает все атрибуты, включая cells, supplementaryviews и decorationviews, что означает, что вы также меняете атрибуты для верхнего и нижнего колонтитулов.

Мы можем изменить код на:

 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributes = super.layoutAttributesForElements(in: rect)

    var leftMargin = sectionInset.left
    var maxY: CGFloat = -1.0
    attributes?.forEach { layoutAttribute in
        //check if the layoutAttribute is for cell
        if layoutAttribute.representedElementCategory == .cell {
                if layoutAttribute.frame.origin.y >= maxY {
                    leftMargin = sectionInset.left
                }

                layoutAttribute.frame.origin.x = leftMargin

                leftMargin  = layoutAttribute.frame.width   minimumInteritemSpacing
                maxY = max(layoutAttribute.frame.maxY , maxY)
            }
    }

    return attributes
}
 

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