Self-sizing UICollectionView with UITableView with dynamic header as a cell

六眼飞鱼酱① 提交于 2021-02-11 13:07:41

问题


I have a problem with making a self sizing UICollectionView with a cell that contains UITableView with a header that has a label with dynamic height.

Can someone point me out to what I need to change in the attached sample project?

You can see on the screenshot that the table does not fit the view as the cell's height is currently manually set.

import UIKit

class ViewController: UIViewController {
    static let section1 = "section1"
        static let section2 = "section2"
        private weak var collectionView: UICollectionView!

        override func viewDidLoad() {
            self.navigationItem.title = "Collection View"
            super.viewDidLoad()
            self.setupCollectionView()
        }

        private func setupCollectionView() {
            let flowLayout = UICollectionViewFlowLayout()
            flowLayout.scrollDirection = .vertical
            flowLayout.minimumInteritemSpacing = 0.0
            flowLayout.minimumLineSpacing = 0.0
            let collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: flowLayout)
            collectionView.alwaysBounceVertical = true
            collectionView.register(
                SectionHeaderView.self,
                forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
                withReuseIdentifier: SectionHeaderView.sectionHeaderId
            )
            collectionView.register(Section1.self, forCellWithReuseIdentifier: ViewController.section1)
            collectionView.register(Section2.self, forCellWithReuseIdentifier: ViewController.section2)
            self.view.addSubview(collectionView)
            self.collectionView = collectionView
            self.collectionView.translatesAutoresizingMaskIntoConstraints = false
            self.collectionView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
            self.collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
            self.collectionView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
            self.collectionView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
            self.collectionView.dataSource = self
            self.collectionView.delegate = self
        }
    }

    // MARK: - UICollectionViewDelegateFlowLayout
    extension ViewController: UICollectionViewDelegateFlowLayout {
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            switch indexPath.section {
            case 0:
                return CGSize(width: self.view.frame.width, height: 210.0)
            case 1:
                return CGSize(width: self.view.frame.width, height: 5 * 51.0 + 130.0) // How to enable self-sizing cells for table view inside
            default:
                fatalError("Unsupported section index.")
            }
        }

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
            return CGSize(width: self.view.frame.width, height: 61)
        }
    }

    // MARK: - UICollectionViewDataSource
    extension ViewController: UICollectionViewDataSource {
        func numberOfSections(in collectionView: UICollectionView) -> Int {
            return 2
        }

        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return 1
        }

        func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
            let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: SectionHeaderView.sectionHeaderId, for: indexPath) as! SectionHeaderView
            switch indexPath.section {
            case 0:
                header.uiLabel.text = "Section 1"
            case 1:
                header.uiLabel.text = "Section 2"
            default:
                fatalError("Unsupported section index.")
            }
            return header
        }

        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            switch indexPath.section {
            case 0:
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewController.section1, for: indexPath) as! Section1
                return cell
            case 1:
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewController.section2, for: indexPath) as! Section2
                return cell
            default:
                fatalError("OverviewController: Unsupported section index.")
            }
        }
}

回答1:


To implement auto-sizing collectionView cells, you really only need a few changes.

Couple key points:

  • Cells must satisfy their own constraints. So, instead of calculating sizing in sizeForItemAt, make sure the cells have width and height constraints. These can be dynamic, based on content.

  • Add elements to the collection view cell's contentView, not to the cell itself.

  • For the embedded non-scrolling table view, use a subclass that sets the intrinsic content size height based on the table's contentSize. Example:


final class ContentSizedTableView: UITableView {
    override var contentSize:CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }
    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

There is a pretty good tutorial here (not mine): https://medium.com/@andrea.toso/uicollectionviewcell-dynamic-height-swift-b099b28ddd23 that has more detailed explanations.

I implement those concepts in the project you made available, and put it up on a GitHub repo (to make it easy to see the changes): https://github.com/DonMag/ThunderCollectionView

Results:



来源:https://stackoverflow.com/questions/58729641/self-sizing-uicollectionview-with-uitableview-with-dynamic-header-as-a-cell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!