Search code examples
ioscocoa-touchuicollectionview

Change collection view cell width at runtime


I'm creating an EPG (Electronic Program Guide); to retrieve the program info I use JSON. For the design, I have a table view in the left half for the channel logo and name, and in the right half a collection view for all the TV programs for that channel. The thing is that for every show the collection view row must have a different width that depends on the duration of the show.

I'm building it based on this fantastic example called: EPG Grid

But in this example, all the channels are loaded previously in one array. This works fine if the channels list is short, but in my case the list is very large, so I need to load every channel in tableView:cellForRowAtIndexPath:, then create the layout with the specified width.

Any thoughts about this?


Solution

  • I figured out by my self, the thing is in my case not to use UICollectionViewLayout (CustomLayout) use layout Flow and add the collectionView inside tableView like this:

    enter image description here enter image description here

    Then in every row of tableView delegate the collectionView.

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    {        
        let cell: CustomTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomTableViewCell
    
        cell.collectionView.delegate = self
        cell.collectionView.dataSource = self
        cell.collectionView.tag = indexPath.row
    
        cell.tag = 100 + indexPath.row;
    
        return cell;
    }
    

    After delegate, the method collectionView:sizeForItemAtIndexPath is called, on this method you must to calculate width or height retrieving data using indexPath

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize 
    {
        //Calculation of width based on indexPath
    
        //...
        return CGSizeMake(width, 89)
    }
    

    Finally for making the scroll uniform for all the cells at the same time use the method scrollViewDidScroll. Check this post: Horizontally scroll ALL rows of UICollectionView together

    func scrollViewDidScroll(scrollView: UIScrollView) {
    
        var ret: Bool = false;
    
        if (self.lastContentOffset > scrollView.contentOffset.x)
        {
            ret = true;
        }
        else if (self.lastContentOffset < scrollView.contentOffset.x)
        {
            ret = true;
        }        
    
        if(scrollView.isKindOfClass(UICollectionView) && ret)
        {
            self.lastContentOffset = scrollView.contentOffset.x;
            for var i = 0; i < data.count; i++
            {
                let cell = self.view.viewWithTag(100 + i) as? ChannelTableViewCell;
    
                if(cell != nil)
                {
                    let collectionCell: UICollectionView? = cell?.collectionView;
    
                    if(collectionCell != nil)
                    {
                        collectionCell!.contentOffset = scrollView.contentOffset;
                    }
                }
            }
        }
    }