LaVOZs

The World’s Largest Online Community for Developers

'; ios - UICollectionView as UITableView subview flow layout loop - LavOzs.Com

I have an UITableView and I want to add a UICollectionView with a horizontal flow layout as subview in the backgroundView of the tableView, to do the same effect of the AppStore. Here I have the implementation code:

in the viewDidLoad:

UIView *tableViewBackgroundView = [[UIView alloc] initWithFrame:self.view.bounds];
    self.tableView.backgroundView = tableViewBackgroundView;

// HighlightView heightFactor returns the reason which is  9.0/16.0
    CGFloat headerViewHeight = CGRectGetWidth(self.view.frame) * [HighlightView heightFactor];
    self.tableView.contentInset = UIEdgeInsetsMake(headerViewHeight, 0, 0, 0);
    self.headerView = [[HighlightView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), headerViewHeight)];
    [tableViewBackgroundView addSubview:self.headerView];

The HighlightView is a view with a collectionView inside.

But I'm having an issue, when the user interacts with the collectionView I start to receive this log:

Please check the values return by the delegate. the behavior of the UICollectionViewFlowLayout is not defined because: the item height must be less than the height of the UICollectionView minus the section insets top and bottom values.

And this becomes a loop that doesn't stop even when the user stops to interact.

HighlightView (CollectionView) code:

override init(frame: CGRect) {
    super.init(frame: frame)
    self.viewModel.delegate = self
    self.configureHighlightsCollectionView()
}

func configureHighlightsCollectionView() {

    let flowLayout = UICollectionViewFlowLayout()
    flowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
    flowLayout.minimumInteritemSpacing = 0
    flowLayout.minimumLineSpacing = 0
    if systemVersion > 8.0 {
        flowLayout.estimatedItemSize = self.frame.size
    }
    flowLayout.itemSize = self.frame.size
    self.highlightsCollectionView = UICollectionView(frame: self.bounds, collectionViewLayout: flowLayout)
    self.highlightsCollectionView.frame = self.bounds
    self.highlightsCollectionView.scrollsToTop = false
    self.highlightsCollectionView.pagingEnabled = true
    self.highlightsCollectionView.registerClass(CachedImageCollectionViewCell.self, forCellWithReuseIdentifier: "ImageCell")
    self.addSubview(self.highlightsCollectionView)

    self.highlightsCollectionView.invalidateIntrinsicContentSize()

    self.highlightsCollectionView.dataSource = self
    self.highlightsCollectionView.delegate = self
    self.highlightsCollectionView.backgroundColor = UIColor.greenColor()

    self.highlightsCollectionView.snp_makeConstraints { (make) -> Void in
        make.top.equalTo(self)
        make.bottom.equalTo(self)
        make.left.equalTo(self)
        make.right.equalTo(self)
    }

}
//Mark: UICollectionViewDataSource
    public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.viewModel.highlightsArray.count
    }

public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageCell", forIndexPath: indexPath) as! CachedImageCollectionViewCell
    cell.highlightData = self.viewModel.highlightsArray[indexPath.item]
    return cell
}

public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    println(self.frame.size)
    return self.frame.size
}

The viewModel is a class who controls the data flow of the collectionView.

First I don't think it's a good idea to put your view as datasource and delegate of your UICollection inside your UIView subclass. You're not respecting the MVC pattern. Learn more informations about it at Introducing iOS Design Pattern . You should set your controller as it.

The problem is you're setting the itemSize of your UICollectionViewFlowLayout in initFrame: based on the frame of your view. In that method, the frame of your UIView is not correct since you're using AutoLayout. You have to wait until AutoLayout calculates the layouts of your views so when layoutSubviews: is called. Learn about UIView and AutoLayout in the Matt's book. It's for iOS 6 and in Objective - C but still great.

Related
How can I disable the UITableView selection?
Eliminate extra separators below UITableView
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
Why is there extra padding at the top of my UITableView with style UITableViewStyleGrouped in iOS7
iOS 8 UITableView separator inset 0 not working
UICollectionView not displayed iOS8
Can't implement required methods of JSQMessagesViewController Swift 3
Issues with casting celltypes to dequeue
Swift Error - Use of undeclared type 'cell' - Collection View