I'm trying to create a UICollectionView programmatically with AutoLayout and I have some issues.
First Test:
In my first try I created a UICollectionView as a Lazy var and added it in the viewDidLoad like this:
lazy var collection: UICollectionView = {
let cv = UICollectionView()
cv.translatesAutoresizingMaskIntoConstraints = false
cv.setCollectionViewLayout(self.flowLayout, animated: true)
cv.dataSource = self
cv.delegate = self
cv.registerClass(MyViewCell.self, forCellWithReuseIdentifier: "cell")
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.collection)
}
This approuch took me to this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'
Second Test:
So I had to use the frame/collectionViewLayout initializer and my second try looked like this:
lazy var collection: UICollectionView = {
let cv = UICollectionView(frame: UIScreen.mainScreen().bounds, collectionViewLayout: self.flowLayout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.setCollectionViewLayout(self.flowLayout, animated: true)
cv.dataSource = self
cv.delegate = self
cv.registerClass(MenuViewCell.self, forCellWithReuseIdentifier: "cell")
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.collection)
//Constraints was there...
}
With this approuch I got a blank screen, using debugger I found out that the datasource delegate methods was called (numberOfItemsInSection
and numberOfSectionsInCollectionView
), but no other delegate methods was called (sizeForItemAtIndexPath
and cellForItemAtIndexPath
)
So I decided to get rid of autoLayout and see the way things work.
Third Test:
lazy var collection: UICollectionView = {
let cv = UICollectionView(frame: UIScreen.mainScreen().bounds, collectionViewLayout: self.flowLayout)
// cv.translatesAutoresizingMaskIntoConstraints = false
cv.setCollectionViewLayout(self.flowLayout, animated: true)
cv.dataSource = self
cv.delegate = self
cv.registerClass(MenuViewCell.self, forCellWithReuseIdentifier: "cell")
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.collection)
//No more constraints here !!!
}
And everything worked fine.
So, my question is: Is there a way to use UICollectionView Programmatically with AutoLayout ?
SOLUTION
After a while, I found out that my problem was in the constraints. Then I came out with this solution:
let slice = (UIScreen.mainScreen().bounds.height / CGFloat(3.0))
lazy var flowLayout:UICollectionViewFlowLayout = {
let f = UICollectionViewFlowLayout()
f.scrollDirection = UICollectionViewScrollDirection.Horizontal
return f
}()
lazy var collection: UICollectionView = {
let cv = UICollectionView(frame: CGRectZero, collectionViewLayout: self.flowLayout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.setCollectionViewLayout(self.flowLayout, animated: true)
cv.dataSource = self
cv.delegate = self
cv.registerClass(MenuViewCell.self, forCellWithReuseIdentifier: "cell")
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.collection)
let views = ["collection":self.collection]
var constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[collection]-0-|", options: NSLayoutFormatOptions.AlignAllTop, metrics: nil, views: views)
self.view.addConstraints(constraints)
constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-\(slice)-[collection]-\(slice)-|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: views)
self.view.addConstraints(constraints)
}
To create a UICollectionView programmatically, I will create a new instance of UICollectionView by giving it a UICollectionViewFlowLayout as a parameter. The above collection view will not display any items however.
Select the Main storyboard from the file browser. Add a CollectionView by pressing command shift L to open the storyboard widget window. Drag the collectionView onto the main view controller. Add constraints to the UICollectionView widget to ensure that the widget fills the screen on all devices.
A layout object that organizes items into a grid with optional header and footer views for each section.
After a while, I figure out that my problem was in the constraints. Then I came out with this solution:
let slice = (UIScreen.mainScreen().bounds.height / CGFloat(3.0))
lazy var flowLayout:UICollectionViewFlowLayout = {
let f = UICollectionViewFlowLayout()
f.scrollDirection = UICollectionViewScrollDirection.Horizontal
return f
}()
lazy var collection: UICollectionView = {
let cv = UICollectionView(frame: CGRectZero, collectionViewLayout: self.flowLayout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.setCollectionViewLayout(self.flowLayout, animated: true)
cv.dataSource = self
cv.delegate = self
cv.registerClass(MenuViewCell.self, forCellWithReuseIdentifier: "cell")
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.collection)
let views = ["collection":self.collection]
var constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[collection]-0-|", options: NSLayoutFormatOptions.AlignAllTop, metrics: nil, views: views)
self.view.addConstraints(constraints)
let stringConstraint = "V:|-\(slice)-[collection]-\(slice)-|"
print("stringConstraint: \(stringConstraint)")
constraints = NSLayoutConstraint.constraintsWithVisualFormat(stringConstraint, options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: views)
self.view.addConstraints(constraints)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With