2

I have a view HeaderView that is subclassing UICollectionReusableView and which is a UIStackView arranging some subviews with labels. The number and texts of those labels depend of the information requested to a service.

Such view is registered to a collectionView this way:

collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: HeaderView.reuseIdentifier)

Then I've implemented collectionView(_:viewForSupplementaryElementOfKind:at:) method like this:

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

    switch kind {
    case UICollectionElementKindSectionHeader:
        if let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind,
                                                                        withReuseIdentifier: HeaderView.reuseIdentifier,
                                                                        for: indexPath) as? HeaderView {

            // Provide the headerView with the texts it needs to show

            return headerView
        }

        fatalError("no view")

    default:
        fatalError("no view")
    }
}

and also implemented collectionView(_:layout:referenceSizeForHeaderInSection:) method.

My issue is that collectionView(_:layout:referenceSizeForHeaderInSection:) is called first, and at that moment the headerView has not been instantiated, so I can't get its actual height. I can't provide a fix height either because, as I said, the height of such headerView will depend on the information I get from a service and it's going to be variable.

I'm not using either storyboard or xib files, I'm creating all the views and setting the layout in code.

I should also add that actually I need this HeaderView to be the header of just one section in my collection view, so I may not need to dequeue and reuse it?

AppsDev
  • 12,319
  • 23
  • 93
  • 186
  • In this case, I suggest to calculate height of stack view and return it with `collectionView(_:layout:referenceSizeForHeaderInSection:)` – trungduc Jul 11 '18 at 11:07
  • I would just have it instantiated in `viewDidLoad` for example and have it stored in a property, thus you will have it ready for `collectionView(_:layout:referenceSizeForHeaderInSection:)` as well. – Ladislav Jul 11 '18 at 12:20
  • @trungduc I've thought about calculating "manually" the height the header view will have, but I think that does not sound very "elegant" and a bit complex maybe... would not be possible to rely somehow on Autolayout? – AppsDev Jul 11 '18 at 12:37
  • @Ladislav it would not work, I think... because I don't know the `frame` the `HeaderView` should have when calling its `init` – AppsDev Jul 11 '18 at 12:58
  • Is your headerView using autolayout? – Ladislav Jul 11 '18 at 13:20
  • Maybe you could `init` it in `viewDidLoad` like I said and save a reference to it, and try to calculate height with `systemLayoutSizeFitting(_ targetSize: CGSize)` method, where you would give it width of collection view and a very big value for height... – Ladislav Jul 11 '18 at 13:23
  • @Ladislav I'm using Autolayout for the `HeaderView` subviews, I'm setting constraints programmatically there – AppsDev Jul 11 '18 at 14:15
  • Did you try if `systemLayoutSizeFitting(_ targetSize: CGSize)` returns the correct size? – Ladislav Jul 11 '18 at 15:01
  • @Ladislav I tried something similar to the 1st answer in this post: https://stackoverflow.com/questions/39825290/make-uicollectionview-header-dynamic-height, and it seems to work if I call `systemLayoutSizeFitting(UILayoutFittingCompressedSize)` instead – AppsDev Jul 11 '18 at 19:01
  • Now the issue is in `viewForSupplementaryElementOfKind`, since I already have a reference for that `HeaderView` and I don't need to dequeue any other one – AppsDev Jul 11 '18 at 19:03
  • What is the issue in `viewForSupplementaryElementOfKind`, you don't have to dequeue it, just return your reference...if all works I can sum everything up in an answer so people will know what the steps were... – Ladislav Jul 12 '18 at 09:48
  • @Ladislav I need to dequeue it, if I dont I get a crash: "'the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath (...) was not retrieved by calling -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: or is nil " – AppsDev Jul 12 '18 at 10:16
  • You probably know the `indexPath` of the `supplementaryView` at the start so just create that `indexPath` and dequeue it like you would inside of the dataSource method... – Ladislav Jul 12 '18 at 10:17

0 Answers0