简体   繁体   中英

Self Sizing CollectionView inside a Self Sizing TableViewCell

I have spent weeks trying to get this to work and have looked at many different suggestions on here, Apple developer forums, Google etc. and am still pulling my hair out. Any help would be greatly appreciated.

I have a ViewController that contains a TableView. It is not a full-screen tableView.

The tableView is built with customTableViewCells that each holds a CollectionView. The problem I have is that the self-sizing collectionView and the self-sizing tableView rows just don't seem to work. I've found a few options online but they only seem to partially work.

This is what I get when it initially runs:

在此处输入图像描述

I'm including a link to the project file as that's probably easier than copying code into here: https://www.dropbox.com/sh/7a2dquvxg62aylt/AACK_TjDxT9eOShZaKi7vLYga?dl=0

Some of the online 'workarounds' don't work in all cases - eg if you tap one of the buttons inside the CollectionView, it is removed and the collectionView (and subsequently the TableView) should resize but again I can't get this to consistently work.

Some of the solutions I've tried:

UICollectionView Self Sizing Cells with Auto Layout

UICollectionView inside a UITableViewCell -- dynamic height?

Dynamic height for a UITableView based on a dynamic collection view

Auto-sizing UITableViewCell which contains UICollectionView

Any help would be greatly appreciated.

I figured out what was wrong. There are a couple things that needed to be fixed:

  1. You need to set an estimated row height (with an actual value) and set the row height as automatic. You did the opposite. So please, replace your setupTableView function with this one below. Also, yo need to set the delegate which you didn't do. So make sure you add UITableViewDelegate next to your class name, and assign it inside of setupTableView() like I did below.

     func setupTableView() { view.addSubview(tempTableView) NSLayoutConstraint.activate([ tempTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tempTableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200), tempTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tempTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -200) ]) tempTableView.rowHeight = UITableView.automaticDimension tempTableView.estimatedRowHeight = 90 tempTableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CustomTableViewCell.cellIdentifier) tempTableView.dataSource = self tempTableView.delegate = self tempTableView.translatesAutoresizingMaskIntoConstraints = false tempTableView.layoutIfNeeded() }
  2. Inside cellForRowAt, add layoutIfNeeded to make sure the cells are auto sized properly:

     extension ViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 2 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tempTableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.cellIdentifier) as. CustomTableViewCell cell.layoutIfNeeded() return cell } }
  3. Your CustomCollectionView needs to subclass UICollectionViewDelegateFlowLayout.

  4. Make sure you assign your configuredCollectionViewLayout variable to your collectionView:

     func setupCollectionView() { backgroundColor =.systemPink isScrollEnabled = false register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.cellIdentifier) dataSource = self self.collectionViewLayout = configuredCollectionViewFlowLayout }
  5. Finally, add these 3 overrides to make your collectionView auto size based on its content (inside CustomCollectionView):

     override var intrinsicContentSize: CGSize { self.layoutIfNeeded() return self.contentSize } override var contentSize: CGSize { didSet{ self.invalidateIntrinsicContentSize() } } override func reloadData() { super.reloadData() self.invalidateIntrinsicContentSize() }

Here is how you trigger a cell redraw upon clicking a button. I'm not using a protocol, but please do, this is just to show you the idea:

func tokenTapped(withTitle title: String) {
    guard let indexOfItemToRemove = tokens.sampleData.firstIndex(where: {$0.name == title}) else { return }
    tokens.sampleData.remove(at: indexOfItemToRemove)
    DispatchQueue.main.async {
        self.performBatchUpdates({
            self.deleteItems(at: [IndexPath(item: indexOfItemToRemove, section: 0)])
        }) { (true) in
            if let tableView = self.superview?.superview?.superview as? UITableView {
                print("tableview updates")
                tableView.beginUpdates()
                tableView.endUpdates()
                DispatchQueue.main.async {
                    tableView.layoutIfNeeded()
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM