Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure a UICollectionView Cell Size per Size Class?

Tags:

I'm finding friction when trying to create responsive / adaptive UICollectionViewCells in the UIStoryboard.

The issue I'm seeing is that you don't seem to be able to set the Cell Size per Size Class and I'm trying to ascertain the right approach to this. I've designed the cells to adjust to their containers, so that they should autosize regardless of size class. This mostly works in that if I change the size class, select my cell view and do Update Frames then they all resize to fit their new size. However it's a one shot deal, if I go back to the Any/Any size class then I'm still seeing that resized version.

Here's what I'm aware I could try:

  • Create multiple cells, with fixed dimensions, one per size class and in the Storyboard view. I could then only use the right one at runtime but I could then see them at design time.
  • I could create a collection view Per Size class, each one only being installed for that size. This would work, but would be a pain to manage the multiple UICollectionViews
  • Create my interface and/or constraints programmatically (losing visibility of the design).

I'm hoping this is a solved scenario and I'm just missing something, but I'm aware that it could be that the IB tools don't match the code at this point.

like image 508
Tristan Warner-Smith Avatar asked Oct 21 '14 15:10

Tristan Warner-Smith


People also ask

How do I set the height and width of a CollectionView cell?

Here's a WWDC video demoing this technique. class MyLayout: UICollectionViewFlowLayout { override func prepare() { super. prepare() guard let collectionView = collectionView else { return } itemSize = CGSize(width: ..., height: ...) } }

How do I make a collection view dynamic height?

Make-CollectionView-Height-Dynamic-According-to-ContentAdd a height constraint to your collection view. Set its priority to 999. Set its constant to any value that only makes it reasonably visible on the storyboard. Change the bottom equal constraint of the collection view to greater or equal.


2 Answers

The solution I came up with was just to implement the UICollectionViewDelegateFlowLayout and implement the sizeForItemAtIndexPath method. This means that the cell dimensions can be set to match the available Size Class dimensions.

This still isn't ideal as you can't see the changes in the storyboard and you can't create a universal design and see it in each of the different formats.

I'm still hoping someone has a better option.

like image 171
Tristan Warner-Smith Avatar answered Nov 13 '22 05:11

Tristan Warner-Smith


Here's a similar solution coded-out in Swift. I just styled both of my cells in the storyboard and leave them viewable for any size class combination. When the trait collection changes I update the cellSize and cellReuseID I want to use and tell the collectionView to reload all the visible cells. Then

collectionView(collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize

and

override func collectionView(collectionView: UICollectionView,
    cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

(not shown in sample code) are called which lets me update the size of the cell and update the cell's storyboard styling. So not entirely done in storyboard, but good enough until more support is provided in Xcode.

struct MyCollectionViewConstants{
    static let CELL_ANY_ANY_REUSE_ID = "cell";
    static let CELL_COMPACT_REGULAR_REUSE_ID = "cellSmall"
    static let CELL_ANY_ANY_SIZE = 100;
    static let CELL_COMPACT_REGULAR_SIZE = 70;
}

class MyCollectionView: UICollectionViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    var cellSize = MyCollectionViewConstants.CELL_ANY_ANY_SIZE
    var cellReuseID = MyCollectionViewConstants.CELL_ANY_ANY_REUSE_ID


    func collectionView(collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{

        return CGSize(width: cellSize, height: cellSize)
    }

    override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact
            && self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClass.Regular){
            cellSize = MyCollectionViewConstants.CELL_COMPACT_REGULAR_SIZE
            cellReuseID = MyCollectionViewConstants.CELL_COMPACT_REGULAR_REUSE_ID
        } else {
            cellSize = MyCollectionViewConstants.CELL_ANY_ANY_SIZE
            cellReuseID = MyCollectionViewConstants.CELL_ANY_ANY_REUSE_ID
        }

        self.collectionView.reloadItemsAtIndexPaths(
            self.collectionView.indexPathsForVisibleItems())
    }
}
like image 39
Martin Woolstenhulme Avatar answered Nov 13 '22 04:11

Martin Woolstenhulme