I am trying to develop an iOS application that has 03 UICollectionViews handled by the same ViewController. (The reason why I am opting for 03 UICollectionViews rather than one with sections and different prototype cells is because I may need to add additional content not relevant to collection views between the sections in the future)
________________
| _ _
| | | | |
| |_| |_| . . . (UICollectionView1)
|_______________
_______________
| _ _
| | | | |
| |_| |_| . . . (UICollectionView2)
|_______________
My problem is as follows:
No of cells in each of the CollectionViews is variable and if the number exceeds the width constraint it wraps down (so far so good). However, the height constraint of the UICollectionView causes a scroll bar to appear rather than simply laying out the cells if the number of cells causes to wrap beyond the height constraint
I have tried a couple of things to get this to work, most of which revolve around the advice given in the following questions
how to set dynamic height of a Collection View, the 'view' not the 'cells'?
In the end I tried this
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: collectionView.contentSize.height)
}
But then the content in the UICollectionViewCell stretched wierdly and still problem of scrolling exists.
I do not mind that the main view of the view controller (the one on which all other UICollectionViews are placed) becomes scrollable (actually that is part of the requirement), I just don't want the UICollectionViews to act like some HTML iframe and allow scrolling but just layout the cells in order for as much as constrained by width of the UICollectionView
In pseudo code, something like this
array = (cell1, cell2, cell3)
for i in array
if currentCollectionViewRow is filled
wrapToNextLine()
add cell{i} to view controller
Any help is appreciated. Even help that suggests better ways to achieve this functionality along with best practices rather than hacking code
EDIT
I carried out the instructions as @Saad Chaudhry mentioned but to no avail. My layout is as follows: CollectionView Layout
As you can see, the stack view encloses both collection views as suggested. Now the IDE gives the following complaints: Ambiguous Layout
I tried adding constraints intuitively, then tried the IDEs options to add constraints automatically to no avail. Most times, there is no data cells on the screen.
For more information, without stack view but just two collection views, I get the following simulation: Without Stack Views
And with stack views I get the simulation: With stack views and note that the second collection view is missing
If I then constraint the stack view at 0,0,0,0, this brings back the issues where each of the collection view heights are ambiguous. Providing heights causes scrolling "within that collection view" if the number of cells are large (from datasource).
I simply want all the black squares to be rendered first and then the yellow squares. The parent view may scroll and that's fine bu not the individual collection views
My code for the controller:
import UIKit
class DemoCollectionViewController: UICollectionViewController {
@IBOutlet weak var nonPriorityCollectionView: UICollectionView!
@IBOutlet weak var priorityCollectionView: UICollectionView!
private let reuseIdentifier = "priorityCell"
fileprivate let sectionInsets = UIEdgeInsets(top: 50.0, left: 20.0, bottom: 50.0, right: 20.0)
fileprivate var priorityItems = [PriorityItem]()
fileprivate let itemsPerRow: CGFloat = 3
private let nonPriorityReuseIdentifier = "nonPriorityCell"
fileprivate var nonPriorityItems = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: nonPriorityReuseIdentifier)
loadPriorityItems()
loadNonPriorityItems()
}
func loadPriorityItems(){
let item1 = PriorityItem(image: #imageLiteral(resourceName: "User"))
let item2 = PriorityItem(image: #imageLiteral(resourceName: "User"))
let item3 = PriorityItem(image: #imageLiteral(resourceName: "User"))
let item4 = PriorityItem(image: #imageLiteral(resourceName: "User"))
priorityItems = [item1, item2, item3, item4, item1, item2, item3, item4]
}
func loadNonPriorityItems(){
let item1 = "Item 1"
let item2 = "Item 2"
let item3 = "Item 3"
let item4 = "Item 4"
nonPriorityItems = [item1, item2, item3, item4]
}
}
// MARK: UICollectionViewDataSource
extension DemoCollectionViewController {
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.priorityCollectionView {
return priorityItems.count
}
else{
return nonPriorityItems.count
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.priorityCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
cell.backgroundColor = UIColor.black
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: nonPriorityReuseIdentifier, for: indexPath)
cell.backgroundColor = UIColor.yellow
return cell
}
}
}
extension DemoCollectionViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let paddingSpace = sectionInsets.left * (itemsPerRow + 1)
let availableWidth = view.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return sectionInsets.left
}
}
Please help me in figuring out this issue. I now feel like collection view is not the ideal way to achieve this due to the complexity I'm facing...