I have two UICollectionViews in one view controller, however my first collection view is conforming to my second collection view's delegate and data source.
The problem is that the category collection view is conforming to the size of the service collection view and it's trying to return five cells.
How do I make my delegate and data source recognize and conform to the two different collection views? Thanks!
My App Screen Image
// HomeController
private let categoryCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 120, height: 120),
collectionViewLayout: UICollectionViewFlowLayout())
private let serviceCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 120, height: 120),
collectionViewLayout: UICollectionViewLayout())
fileprivate func configureUI() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
popularCategoryCardView.addSubview(categoryCollectionView)
categoryCollectionView.backgroundColor = .white
categoryCollectionView.collectionViewLayout = layout
categoryCollectionView.isScrollEnabled = true
categoryCollectionView.delegate = self
categoryCollectionView.dataSource = self
categoryCollectionView.register(CategoryCell.self, forCellWithReuseIdentifier: CellIdentifiers.CategoryCell)
categoryCollectionView.anchor(left: popularCategoryCardView.leftAnchor, bottom: popularCategoryCardView.bottomAnchor,
right: popularCategoryCardView.rightAnchor, paddingLeft: 8, paddingBottom: 8, paddingRight: 8, height: 120)
popularServiceCardView.addSubview(serviceCollectionView)
serviceCollectionView.backgroundColor = .white
serviceCollectionView.collectionViewLayout = layout
serviceCollectionView.isScrollEnabled = true
serviceCollectionView.delegate = self
serviceCollectionView.dataSource = self
serviceCollectionView.register(ServiceCell.self, forCellWithReuseIdentifier: CellIdentifiers.ServiceCell)
serviceCollectionView.anchor(left: popularServiceCardView.leftAnchor, bottom: popularServiceCardView.bottomAnchor,
right: popularServiceCardView.rightAnchor, paddingLeft: 8, paddingBottom: 8, paddingRight: 8, height: 150)
}
// MARK: - UICollectionViewDataSource
extension HomeController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.categoryCollectionView {
return jobCategory.count
} else {
return 5
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.categoryCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifiers.CategoryCell, for: indexPath) as! CategoryCell
cell.jobCategory = jobCategory[indexPath.item]
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifiers.ServiceCell, for: indexPath) as! ServiceCell
return cell
}
}
}
// MARK: - UICollectionViewDelegateFlowLayout
extension HomeController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == self.categoryCollectionView {
return CGSize(width: 160, height: 120)
} else {
return CGSize(width: 100, height: 140)
}
}
}
Don't use the same layout object for multiple collection views:
let categoryLayout = UICollectionViewFlowLayout()
categoryLayout.scrollDirection = .horizontal
categoryCollectionView.collectionViewLayout = categoryLayout
let serviceLayout = UICollectionViewFlowLayout()
serviceLayout.scrollDirection = .horizontal
serviceCollectionView.collectionViewLayout = serviceLayout
Related
I have a UICollectionView that I have implemented to scroll horizontally but for some reason when I scroll through there are only 3 cells that are presented (when there should be 9)
class BusinessPhotosViewController: UICollectionViewController ,UICollectionViewDelegateFlowLayout{
let cellId = "photos"
override func viewDidLoad() {
super.viewDidLoad()
if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
}
collectionView?.register(BusinessPhotoCells.self, forCellWithReuseIdentifier: cellId)
collectionView?.contentInset = UIEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
collectionView?.scrollIndicatorInsets = UIEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
collectionView?.isPagingEnabled = true
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 9
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! BusinessPhotoCells
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = view.frame.width / 3
return CGSize(width: width, height: width)
}
}
I present this BusinessPhotosViewController within the cell of ANOTHER UICollectionViewController called BusinessDetailViewController
class BusinessDetailViewController : UICollectionViewController {
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let scrollCell = collectionView.dequeueReusableCell(withReuseIdentifier: pictureCellId, for: indexPath)
let bizVC = BusinessPhotosViewController(collectionViewLayout: UICollectionViewFlowLayout())
scrollCell.addSubview(bizVC.view)
bizVC.view.anchor(top: scrollCell.topAnchor, left: scrollCell.leftAnchor, bottom: scrollCell.bottomAnchor, right: scrollCell.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: scrollCell.frame.width, height: scrollCell.frame.height)
return scrollCell
}
}
So I can see that the scrolling works, but the issue I'm seeing is that only 3 cells are loaded (out of 9) and the view looks something like this:
I've seen these solutions here and here and other but none helped me.
I tried your code and I can see all the 9 cells if the size of 9 cell is smaller than the size scroll cell size.
import UIKit
class ViewController: UIViewController{
override func viewDidLoad() {
view.backgroundColor = .red;
view.addSubview(photosContainer);
photosContainer.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true;
photosContainer.topAnchor.constraint(equalTo: view.centerYAnchor).isActive = true;
photosContainer.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true;
photosContainer.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.4).isActive = true;
***let layout = UICollectionViewFlowLayout();
layout.scrollDirection = .horizontal
let bizVC = BusinessPhotosViewController(collectionViewLayout: layout)
bizVC.view.frame = photosContainer.bounds;
photosContainer.addSubview(bizVC.view)***
}
let photosContainer : UIView = {
let view = UIView();
view.backgroundColor = .green;
view.translatesAutoresizingMaskIntoConstraints = false;
return view;
}();
}
Before adding the view if you set the frame then I can see all the nine cells no matter their size.
Let me know if it works
It's been a while since I programmatically created a collection view and I can't seem to find why my cells are not showing. Delegate and Datasource are being set. Size is being set and it is not too big.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
setupCV()
}
var containerCollectionView: UICollectionView = {
let layout = UICollectionViewLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.white
return cv
}()
}
extension ViewController {
fileprivate func setupCV() {
// these first two lines add the colelction view and apply constraints - they work and the CV is properly displayed inside the view controller
self.view.addSubview(containerCollectionView)
containerCollectionView.anchor(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
containerCollectionView.delegate = self
containerCollectionView.dataSource = self
containerCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 150, height: 150)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = UIColor.yellow
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
}
You are initializing the wrong layout.
try this:
let layout = UICollectionViewFlowLayout()
I have a problem with UICollectionView. I created a collection with FlowLayout and I'm trying to resize only second item to make it width to 2xcellWidth. It's ok when View is appear, but after that, when I'm scrolling and back to top, my cell are disappear, reorder or change it width. It's totally weird behave.
So to be clear: I created collection view, scroll to bottom and when I back to top, I see my cells are in some weird place like this:
before:
after:
class MapEventsViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate {
var collectionView: UICollectionView!
let screenWidth = UIScreen.main.bounds.width
let options = [Options(id: "", value: "28-03-2017 10:54:01"),
Options(id: "", value: "Berlin Strasse 6A 00-000, Berlin", isDoubled: true),
Options(id: "Status", value: "-"),
Options(id: "Prędkość", value: "40km/h"),
Options(id: "Licznik", value: "250000km"),
Options(id: "Napięcie", value: "15V")]
override func viewDidLoad() {
super.viewDidLoad()
view.frame.size.height = 170
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 1, left: 0, bottom: 0, right: 1)
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 0
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(MapEventCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.backgroundColor = UIColor.white
collectionView.isScrollEnabled = true
collectionView.alwaysBounceVertical = true
collectionView.autoresizingMask = UIViewAutoresizing.flexibleWidth
collectionView.backgroundColor = UIColor.init(white: 0.90, alpha: 1.0)
collectionView.showsVerticalScrollIndicator = true
self.view.addSubview(collectionView)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return options.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MapEventCell
cell.awakeFromNib()
cell.id.font = UIFont.systemFont(ofSize: 12)
cell.value.font = UIFont.boldSystemFont(ofSize: 14)
cell.backgroundColor = UIColor.white
if indexPath.row == 0{
cell.value.font = UIFont.systemFont(ofSize: 10)
cell.value.frame.origin.y -= 6
}
if indexPath.row == 1{
cell.value.font = UIFont.systemFont(ofSize: 10)
cell.value.frame.origin.y -= 6
}
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let thisCell = cell as! MapEventCell
thisCell.id.text = options[indexPath.item].id
thisCell.value.text = options[indexPath.item].value
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// print("sizeForItemAt")
let cellWidth = UIScreen.main.bounds.width / 3 - 1
if options[indexPath.item].isDoubled{
return CGSize(width: cellWidth * 2 + 1, height: 40)
}
return CGSize(width: cellWidth, height: 40)
}
}
class MapEventCell: UICollectionViewCell{
var id: UILabel = UILabel()
var value: UILabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
print("addViews")
id.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: 16)
id.textAlignment = .center
value.frame = CGRect(x: 0, y: 16, width: contentView.frame.width, height: 20)
value.textAlignment = .center
// id.font = UIFont.systemFont(ofSize: 12)
id.textColor = UIColor.lightGray
// value.font = UIFont.boldSystemFont(ofSize: 14)
contentView.addSubview(id)
contentView.addSubview(value)
}
override func prepareForReuse() {
id.removeFromSuperview()
value.removeFromSuperview()
}
}
UPDATE
I've solved this problem by calculating frame of each element in cell at CellForItemAt indexPath. So now it looks like this (and worked):
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MapEventCell
cell.awakeFromNib()
cell.backgroundColor = UIColor.white
if indexPath.section == 0{
cell.value.frame = CGRect(x: 0, y: 0, width: (screenWidth / 3), height: 30)
if options[indexPath.item].isDoubled {
cell.value.frame = CGRect(x: 0, y: 0, width: (screenWidth / 3) * 2 - 2, height: 30)
cell.value.textAlignment = .center
}
cell.id.isHidden = true
cell.value.font = UIFont.systemFont(ofSize: 10)
}else{
//cell.frame = CGRect(x: 0, y: 0, width: (screenWidth / 3) - 1, height: 40)
cell.id.isHidden = false
cell.id.font = UIFont.systemFont(ofSize: 10)
cell.value.font = UIFont.boldSystemFont(ofSize: 12)
}
return cell
}
But now I'm not sure is it good solving. I know that every time cells are reusing, so my question is, are there better solutions for this problem?
I am having a UICollectionView that I create and add programatically but for some reason at runtime section 1 and section 2 are overlapping, they both start in the same place:
Here is my Implementation (the code is swift 2.3 since this is a project requirement):
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = lightGreyColor
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0)
layout.minimumInteritemSpacing = 0.5
layout.minimumLineSpacing = 0.5
layout.scrollDirection = UICollectionViewScrollDirection.Vertical
// layout.headerReferenceSize = CGSize(width: view.bounds.width, height: 30)
let collectionViewFrame = CGRect(x: 0, y: 0, width: view.bounds.width, height: viewHeight)
collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
collectionView.allowsSelection = true
collectionView.bounces = true
collectionView.scrollEnabled = true
collectionView.hidden = false
collectionView.pagingEnabled = false
collectionView.backgroundColor = lightGreyColor
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.delegate = self
collectionView.dataSource = self
view.addSubview(collectionView)
collectionView.registerNib(UINib(nibName: "SmallDiscoverItemCollectionViewCell", bundle: NSBundle.mainBundle()), forCellWithReuseIdentifier: "SmallDiscoverItemCollectionViewCell")
collectionView.registerClass(NewDiscoverTopCollectionViewCell.self, forCellWithReuseIdentifier: "NewDiscoverTopCollectionViewCell")
collectionView.registerClass(TopHeaderCell.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "TopHeaderCell")
greedoCollectionViewLayout = nil
greedoCollectionViewLayout1().rowMaximumHeight = collectionView.bounds.width/1.8
greedoCollectionViewLayout1().fixedHeight = false
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
switch indexPath.section {
case 0:
return CGSize(width: collectionView.bounds.width, height: 200)
case 1:
return CGSize(width: collectionView.bounds.width, height: 200)
default:
return self.greedoCollectionViewLayout1().sizeForPhotoAtIndexPath(indexPath)
}
}
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
switch (indexPath.section) {
case 0: let cell = collectionView.dequeueReusableCellWithReuseIdentifier("NewDiscoverTopCollectionViewCell", forIndexPath: indexPath) as! NewDiscoverTopCollectionViewCell
return cell
case 1: let cell = collectionView.dequeueReusableCellWithReuseIdentifier("NewDiscoverTopCollectionViewCell", forIndexPath: indexPath) as! NewDiscoverTopCollectionViewCell
return cell
case 2: let cell = collectionView.dequeueReusableCellWithReuseIdentifier("SmallDiscoverItemCollectionViewCell", forIndexPath: indexPath) as! SmallDiscoverItemCollectionViewCell
let item = usersItems[indexPath.item]
return cell
}
This is the end result of the overlap: Section 0 and 1 and having green background while in between there is this gap. While section 2 has lots of images:
For some weird reason the UICollectionViewCell got initialise to a y position equal to its size. To fix that I have just added this in the UICollectionViewCell
override init(frame: CGRect) {
let noProblemFrame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
super.init(frame: noProblemFrame)
I have a UIViewController setup that also contains a UICollectionView inside of it. This Collection view has multiple cells, each of which I would like to make display an image. The images are contained in an array called imageThumbsAray. Each cell is a 90x90 square and I would like the image to fill the content area of each cell. Below is my code for the collection view. It seems to be correct, but when I run the app, I am returned with an empty collection view.
func SetupCollectionView() {
let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 90, height: 90)
PastObjectsCollection = UICollectionView(frame: CGRect(x: 16, y: 229, width: 368, height: 368), collectionViewLayout: layout)
PastObjectsCollection!.dataSource = self
PastObjectsCollection!.delegate = self
PastObjectsCollection!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier:"Chow Object Reuse ID")
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return objectsCount
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Chow Object Reuse ID", forIndexPath: indexPath) as UICollectionViewCell
cell.backgroundColor = UIColor.whiteColor()
var imageView:UIImageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)
imageView.image = imageThumbsArray[indexPath.row]
cell.addSubview(imageView)
return cell
}
Why is the Collection view not creating the cells?
Thanks,
Siddharth
This code use as much of your code as as I could. You can compare line by line. I did't have your image assets or object array. This is all programmatic. Let me know if you need more help.
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var PastObjectsCollection:UICollectionView?
var layout:UICollectionViewFlowLayout?
override func viewDidLoad() {
super.viewDidLoad()
SetupCollectionView()
}
func SetupCollectionView() {
self.layout = UICollectionViewFlowLayout()
self.layout!.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
self.layout!.itemSize = CGSize(width: 90, height: 90)
self.PastObjectsCollection = UICollectionView(frame: CGRect(x: 16, y: 229, width: 368, height: 368), collectionViewLayout: layout!)
self.PastObjectsCollection!.dataSource = self
self.PastObjectsCollection!.delegate = self
self.PastObjectsCollection!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier:"Chow Object Reuse ID")
self.PastObjectsCollection!.backgroundColor = UIColor.blackColor()
self.view.addSubview(self.PastObjectsCollection!)
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1 //objectsCount
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Chow Object Reuse ID", forIndexPath: indexPath) as UICollectionViewCell
cell.backgroundColor = UIColor.whiteColor()
var imageView:UIImageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)
//imageView.image = imageThumbsArray[indexPath.row]
cell.addSubview(imageView)
return cell
}
}