I have a UICollectionView with a button to create cells, which should appear in the order of creation (1,2,3,4 across and down as space permits). The text views are constrained with flexible widths to fill the cell. The size of the cell depends on the device and rotation to allow 1, 2, 3 or 4 cells per row as follows:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
var size = collectionView.bounds.size // size of collection view
switch size.width
{
case 0...450:
println(size.width)
return CGSize(width: (size.width - 10), height: 145)
case 451..<768:
println(size.width)
return CGSize(width: ((size.width - 10) / 2), height: 145)
case 768:
println(size.width)
return CGSize(width: ((size.width - 10) / 3), height: 145)
default:
println(size.width)
return CGSize(width: 248, height: 150) // in case there is no size
}
}
With left and right insets set to 0, this sort of works - but only if I rotate the device and add a cell. In detail:
- Simulating an iPhone 5, if cells are added in portrait they appear below each other, as intended, but when the device is rotated, the cells remain in a vertical column instead of two cells per row. If I add a cell while in landscape, the cells then arrange themselves two cells per row, which is correct (except for having to add a cell to make it happen).
- Simulating an iPad, if cells are added in portrait, instead of three, only two cells are added per row with space for a third cell between them.
- Continuing on iPad, if the device is rotated, instead of four, only three cells appear in each row with space between them. Similar to the iPhone, if another cell is added while in landscape mode, four cells appear per row as expected, AND if the device is rotated back to portrait, three cells are positioned per row, which is correct (except for having to rotate the device, add a cell and rotate it back).
I am calling reloadData when adding the cells, and if I understand correctly, I should not have to call reload upon device rotation (called automatically). Why do I have to rotate the device to landscape and add a cell for the correct layouts to appear in both orientations?
As requested, here is a thinned out version of the source code for the VC. With a simple cell (244*150 with text field 228) and button in the footer, this should repeat the problem:
import UIKit
class CountCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout
{
private var reuseIdentifier = "CountCell"
var cells = 1
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
@IBAction func addCount(sender: AnyObject)
{
cells += 1
self.collectionView?.reloadData()
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
{
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return cells
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as UICollectionViewCell
return cell
}
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView
{
switch kind // the kind of supplimentary view provided by layout
{
case UICollectionElementKindSectionFooter: // section header was selected in storyboard
let footerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "CountFooterView", forIndexPath: indexPath) as UICollectionReusableView // deque and select correct header
return footerView
default:
assert(false, "Unexpected element kind")
}
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
var size = collectionView.bounds.size
switch size.width
{
case 0...450:
return CGSize(width: (size.width - 20), height: 145)
case 451..<768:
return CGSize(width: ((size.width - 20) / 2), height: 145)
case 768:
return CGSize(width: ((size.width - 20) / 3), height: 145)
default:
return CGSize(width: 248, height: 150)
}
}
private let sectionInsets = UIEdgeInsets(top: 20.0, left: 0, bottom: 50.0, right: 0.0)
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets
{
return sectionInsets
}
}