Demo for Collection View on iOS with auto layout in UICollectionViewCell to create cells with dynamic heights
Works on iOS7, iOS8 and iOS9.
Updated to Swift 2.1.1 Demo can now be displayed in all iPhone screen sizes.
For off screen cells, there's a new dynamic collection view which will handle it gracefully. Check it out! ZHDynamicCollectionView
Cell is created in xib file, can be also created in code.
Cell is a basic cell with a title label and a content label. Title label has 1 line text and content label has multiple lines text.
There are totally 7 constraints for two labels:
For the title label, there are top, leading, trailing spacing with superView. For the content label, there are bottom, leading, trailing spacing with superView. And there is a fixed vertical spacing between the bottom of the title label with the top of the content label
All of these 7 constraints have 1000 priority
For two labels, set their Content Hugging Priority and Content Compression Resistance Priority same as following pic:
Subclassing this UICollectionViewCell
In awakeFromNib()
, for iOS7 remember to set
self.contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
and in layoutSubviews()
Set contentLabel.preferredMaxLayoutWidth
to a preferred value, like contentLabel.preferredMaxLayoutWidth = self.bounds.width - 2 * kLabelHorizontalInsets
You may also need a configure function, make sure in this function, call self.setNeedsLayout()
and self.layoutIfNeeded()
In collectionView's view controller, two key delegate methods are collectionView:layout:sizeForItemAtIndexPath:
and cellForItemAtIndexPath:
Since collectionView:layout:sizeForItemAtIndexPath:
is called before cellForItemAtIndexPath:
, so we need to initialize a cell and let system use auto layout to calculate height for us. To avoid memory leak, we use a dictionary to cache the cells that are off screen (not shown on screen)
The dictionary variable is var offscreenCells = Dictionary<String, UICollectionViewCell>()
In collectionView:layout:sizeForItemAtIndexPath:
, first create or retrieve a cell
var cell: MyCollectionViewCell? = self.offscreenCells[reuseIdentifier] as? MyCollectionViewCell
if cell == nil {
cell = NSBundle.mainBundle().loadNibNamed("MyCollectionViewCell", owner: self, options: nil)[0] as? MyCollectionViewCell
self.offscreenCells[reuseIdentifier] = cell
}
Once a cell is initialized, its size is determined by size in xib file, thus, we need configure texts in cell and layoutSubviews, this will let system recalculate the size of cell
// Config cell and let system determine size
cell!.configCell(titleData[indexPath.item], content: contentData[indexPath.item], titleFont: fontArray[indexPath.item] as String, contentFont: fontArray[indexPath.item] as String)
// Cell's size is determined in nib file, need to set it's width (in this case), and inside, use this cell's width to set label's preferredMaxLayoutWidth, thus, height can be determined, this size will be returned for real cell initialization
cell!.bounds = CGRectMake(0, 0, targetWidth, cell!.bounds.height)
cell!.contentView.bounds = cell!.bounds
// Layout subviews, this will let labels on this cell to set preferredMaxLayoutWidth
cell!.setNeedsLayout()
cell!.layoutIfNeeded()
Once cell is updated, call var size = cell!.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
to get the size for this cell.
In cellForItemAtIndexPath:
, cell also need configured and layout its subviews
Copyright (c) 2014 Honghao Zhang
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.