My app has a UIViewController
class; inside this class I connect a UICollectionView
loaded from a Storyboard.
I'm creating a custom layout with the UICollectionViewLayout
class. Here's what it looks like:
class MyLayout: UICollectionViewLayout {
override func prepareLayout() {
super.prepareLayout()
}
override func collectionViewContentSize() -> CGSize {
let attributes = super.collectionViewContentSize()
return attributes
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
let attributes = super.layoutAttributesForElementsInRect(rect) as? [UICollectionViewLayoutAttributes]
return attributes
}
override func layoutAttributesForItemAtIndexPath(indexPath:
NSIndexPath) -> UICollectionViewLayoutAttributes {
let attributes = super.layoutAttributesForItemAtIndexPath(indexPath)
return attributes
}
}
To assign a UICollectionViewLayout
to the UICollectionView
, I use the collectionViewLayout
property of the UICollectionView
:
myCollectionView.collectionViewLayout = MyLayout()
Running the app, the UICollectionViewCells
are no longer visible. Though, they were visible before assigning the UICollectionViewLayout
. I can now only see the background of the UICollectionView
.
Why are cells no longer visibile?
Update
I looked carefully at the UICollectionViewLayoutAttributes
of my UICollectionView
, particularly the contentSize
. I printed out its value and it seems to be equal to (0.0, 0.0)
. The attributes
value for layoutAttributesForElementsInRect
is also equal to nil
. Definitely a red flag.
I think you can keep almost everything exactly the same. Change the class type of your custom layout to
UICollectionViewFlowLayout
.Also, change myLayout to MyLayout for good measure :)
First of all, you should be initializing your UICollectionView with your layout instead of setting it afterward:
From the documentation:
Next, if you subclass
UICollectionViewLayout
, you must implementcollectionViewContentSize
and return a value of your own. Calling super is undefined here, unless you are subclassingUICollectionViewFlowLayout
.That's because UICollectionViewLayout as itself is an abstract class that does nothing (it is meant to be subclassed).
In the same way, you also need to compute your own layoutAttributes in
layoutAttributesForElementsInRect:
. The easiest is to compute all your required layout in theprepareLayout
method, and just get the ones you need afterwards. This is the "core" of a custom layout:UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
.frame
property of that layoutAttribute.layoutAttributesForElementsInRect:
, iterate through all your stored layoutAttributes previously instantiated, and return a subset of those with theirframe
intersecting the providedrect
. The UICollectionView will ask its dataSource to provide a cell for every layoutAttributes returned by that method (viacellForItemAtIndexPath
), and theframe
of those cells will be set using theframe
property in those layoutAttributes.If you can read Objective-C as well as Swift, you could take a look at my sample
UICollectionViewLayout
implementation here, which makes the UICollectionView mimic the daily view of the iOS calendar app (screenshot).If your goal is to achieve a layout that if fairly standard (i.e. elements disposed in a grid that flows horizontally or vertically), I'd recommend you to start by subclassing
UICollectionViewFlowLayout
instead, as it is already a valid implementation ofUICollectionViewLayout
, meaning you could usesuper
in most methods to get the default values.Also, a good read here in the official documentation on how to create your own custom layout.