5

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?

Sahil Kapoor
  • 10,322
  • 10
  • 57
  • 82
  • seldom use it in this way, when you decide to use UICollectionView, in most case, there is no need to use UITableView to contain it I think. – childrenOurFuture Jul 21 '16 at 03:51
  • @Jean Baptiste, Did the accepted answer solve your problem? I am doing exactly the same as your code but when I use UITableViewAutomaticDimension my collection view doesn't bind at all. could you give me a hint please? – Masoud Dadashi Feb 01 '17 at 20:52

2 Answers2

1

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

Rakesh Mandloi
  • 341
  • 2
  • 11
0

In order to solve my problem, I created an array to store the height of each cell of the UITableView (named cellHeight).

I also calculate the height of each cell at the start of the program in an array composed of array (named cellHeightForPost). The main array represent all the TableView cells, each array inside it represent the height of each cell of the 'collectionView'

In order to update the table view everytime I change the collectionView inside it, i used the fonction collectionView(... willDiplayCell...) :

self.tableView.beginUpdates()
cellHeight[collectionView.tag] = cellHeightForPost[collectionView.tag][indexPath.row]
self.tableView.setNeedsLayout()
self.tableView.layoutIfNeeded()
self.tableView.endUpdates()

My UITableView size is defined in tableView(... heightForRowAtIndexPath) and tableView(... estimatedHeightForRowAtIndexPath) :

return cellHeight[indexPath.row]

To set the size of the collectionViewCells :

return CGSize(width: collectionView.frame.width, height: cellHeightForPost[collectionView.tag][indexPath.row])