Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Expand UITableViewCell height depending on the size of the UICollectionView inside it

Hi everyone. I started learning programming 1 month ago so please be nice if I don't explain my problem well :)

My project is composed of a main UITableView. In each cell of the UITableView, I have a UICollectionView (on horizontal scrolling).

Img 1 : Main view

The width of each UICollectionViewCell is the same as the entire UITableViewCell. My first problem is about sizing the height of the UITableViewCell (which will depend of the size of the UICollectionView itself and the size of the content on top of it).

Img 2 : CollectionView

This has to be done automatically. In fact, the UICollectionViewCells will not have the same height, so when the user will scroll the UICollectionView horizontally, a new UICollectionViewCell will appear (with different height) and the height of the UITableViewCell will have to adapt.

The second problem I have is about sizing the UICollectionViewCell, in fact I will not know in advance what the height of it is going to be (the width is the same as the UITableView). I should import the content from a nib.

So now here is my ViewController file,

the variables:

@IBOutlet weak var tableView: UITableView!
var storedOffsets = [Int: CGFloat]()

the UITableView extension : Create the cell of the UITableView and set delegate of UICollectionView inside it

extension IndexVC: UITableViewDelegate, UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 6 //Temp
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCellWithIdentifier("CellCollectionView") as? CellPost {
        let post = self.posts[indexPath.row]
        cell.configureCell(post)

        return cell
    } else {
        return CellPost()
    }

}

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    guard let tableViewCell = cell as? CellPost else { return }

    tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
    tableViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}

func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    guard let tableViewCell = cell as? CellPost else { return }

    storedOffsets[indexPath.row] = tableViewCell.collectionViewOffset
}

the part of the UICollectionView : Add the view from a Nib/xib to the cell

extension IndexVC: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 9 //Temp
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellInCollectionView", forIndexPath: indexPath)

    if let textPostView = NSBundle.mainBundle().loadNibNamed("textPostView", owner: self, options: nil).first as? textPostView {
        textPostView.configurePost(post.descriptionLbl)
        cell.addSubview(textPostView)
        textPostView.translatesAutoresizingMaskIntoConstraints = false
        cell.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":textPostView]))
        cell.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":textPostView]))

    }

    return cell
}

Make the size of the cell the same as the entire UICollectionView

extension IndexVC: UICollectionViewDelegateFlowLayout {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSizeMake(collectionView.frame.width, collectionView.frame.height)
}

And I created this extension in the class dedicated for the UITableViewCell (not useful for the problem, but if any of you want to recreate it)

extension CellPost {
func setCollectionViewDataSourceDelegate<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>(dataSourceDelegate: D, forRow row: Int) {

    collectionView.delegate = dataSourceDelegate
    collectionView.dataSource = dataSourceDelegate
    collectionView.tag = row
    collectionView.setContentOffset(collectionView.contentOffset, animated:false) // Stops collection view if it was scrolling.
    collectionView.reloadData()
}

var collectionViewOffset: CGFloat {
    set {
        collectionView.contentOffset.x = newValue
    }

    get {
        return collectionView.contentOffset.x
    }
}

If anyone want to use this code, it works great, but I have to hardcode the height of the UITableView with a tableView( ... heightForRowAtIndexPath ...)

I tried everything to make the UITableViewCell adapt to what's inside it (I tried calculating the size of content sent by the Nib I'm putting in the cell, and then send it to tableView( ... heightForRowAtIndexPath ...) but I can't make it work. I also tried Auto Layouts but maybe I'm doing it wrong. I also think the problem could come from the part that I imported the nib in my cell.

I also have no idea of a way to expand the cell after the user has swiped the UICollectionViewCell, is there any way to create an event when that happens? And maybe call tableView( ... heightForRowAtIndexPath ...) again?

like image 748
Jean-Baptiste Terrazzoni Avatar asked Nov 08 '22 12:11

Jean-Baptiste Terrazzoni


1 Answers

As i understanding you need to auto adjust tableview cell height. so you can use autolayout for adjust cell height.

Write in ViewDidLoad

self.tableView.estimatedRowHeight = 80
self.tableView.rowHeight = UITableViewAutomaticDimension

Before Returning cell in CellForRowAtIndexPath

self.tableView.setNeedsLayout()
self.tableView.layoutIfNeeded()

You can find link for autolayout. enter link description here

like image 119
Rakesh Mandloi Avatar answered Nov 15 '22 06:11

Rakesh Mandloi