UICollectionView dynamici c размер заголовка - PullRequest
0 голосов
/ 06 апреля 2020

У меня есть collectionView с заголовком, созданным в файле .xib. Он имеет простую метку, и его текст поддерживает dynamicType.

Как я могу установить высоту этого заголовка как Dynami c на основе этой метки и ограничений автоматического макета в раскадровке?

Пока что у меня есть это:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    let kind = UICollectionView.elementKindSectionHeader
    let indexPath = IndexPath(row: 0, section: section)
    if let headerView = collectionView.supplementaryView(forElementKind: kind, at: indexPath) as? SectionHeaderView {
        headerView.layoutIfNeeded()
        headerView.setNeedsLayout()
        let size = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
        return size
    }
    return CGSize(width: 0, height: 0)
}

Но он не показывает никакого заголовка.

SectionHeaderView.xib выглядит так: header.xib

CollectionView выглядит так: вы видите 3 раздела, но не видите заголовка. collectionView

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

1 Ответ

1 голос
/ 06 мая 2020

Используйте пользовательский макет потока , чтобы идеально управлять высотой заголовка в представлении коллекции с помощью функции Dynamic Type.

Элемент заголовка рассматривается как дополнительный элемент для представления коллекции и referenceSizeForHeaderInSection 'метод' используется только для инициализации: он не вызывается с функцией Dynamic Type. 101

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

Все, что запускается методом invalidateLayout, вызываемым в traitCollectionDidChange, запускается, когда пользователь изменяет размер шрифта. 10

ШАГ 1 ⟹ создайте простой пользовательский класс заголовка, например, следующим образом:

class MyHeaderClass: UICollectionReusableView {

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

    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
}

ШАГ 2 ⟹ создайте новый пустой. xib добавляет повторно используемое представление и назовите его точно таким же именем, как и класс, к которому он относится: не забудьте изменить имя этого класса в регистре Identity Inspector.

STEP 3 ⟹ XIB-файл в контроллере:

collectionView.register(UINib(nibName: collectionViewHeaderFooterReuseIdentifier bundle: nil),
                        forSupplementaryViewOfKind: UICollectionElementKindSectionHeader,
                        withReuseIdentifier:collectionViewHeaderFooterReuseIdentifier)

ШАГ 4 ⟹ поддерживает эту новую ячейку в вашем источнике данных (заголовок является дополнительным элементом для представления коллекции) :

func collectionView(_ collectionView: UICollectionView,
                    viewForSupplementaryElementOfKind kind: String,
                    at indexPath: IndexPath) -> UICollectionReusableView {

    if (kind == UICollectionView.elementKindSectionHeader) {
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind,
                                                                         withReuseIdentifier: collectionViewHeaderReuseIdentifier,
                                                                         for: indexPath) as! MyHeader
        headerView.myLabel.text = "Your Header Title"
        return headerView
    } else {
        return UICollectionReusableView(frame: CGRect.null) }
}

... и в вашем делегате (это инициализирует размер заголовка и делает его видимым) :

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

    return CGSize(width: collectionView.frame.width, height: headerHeight)
}

.. после добавления глобальный var headerHeight: CGFloat = 90.0 для инициализации.

ШАГ 5 ⟹ создайте пользовательский макет потока для адаптации высоты заголовка к новому размеру шрифта:

class FlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        let layoutAttributes = super.layoutAttributesForElements(in: rect)

        layoutAttributes?.forEach({ (attribute) in
            if (attribute.representedElementKind == UICollectionView.elementKindSectionHeader) {

                headerHeight = UIFontMetrics.default.scaledValue(for: 22.0)
                attribute.frame.size.height = headerHeight
            }
        })

        return layoutAttributes
    }
}

Don ' не забудьте обновить раскадровку в Interface Builder: enter image description here STEP 6 ⟹ информировать контроллер о необходимости запуска обновления макета, когда пользователь изменяет размер шрифта:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    if (previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory) {
        collectionView?.collectionViewLayout.invalidateLayout()
    }
}

Следуя этому обоснованию, автоматически устанавливается правильная высота заголовков в соответствии с размером шрифта заголовков ⟹ Я предлагаю использовать Новая функция Xcode 11 для очень быстрого тестирования Dynamic Type. ?

...