Unable to display multiple UICollectionViewCells with Swift - ios

I am unable to display the second cell despite registering it to the collectionView. Does anyone know why this is the case? The cell exists as when I switch the row the other cell displays instead.
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.white
collectionView?.register(HeaderCell.self, forCellWithReuseIdentifier: "HeaderCell")
collectionView?.register(SummaryCell.self, forCellWithReuseIdentifier: "SummaryCell")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 1
}
return 1
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (indexPath.row == 0) {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
return cell1
} else {
let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "SummaryCell", for: indexPath) as! SummaryCell
return cell2
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
}
I have looked a this but still unable to get it to work.
P.S. I am programming everything programmatically.

You have registered 2 cells but you are returning only 1 row.Try returning 2 items.
//numberOfItemsInSection
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return 2
}

None of the answer correctly/completely solves the issue. However I did use some of the suggestions to get it to work properly by adding the following:
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
And changing indexPath.row to indexPath.section
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (indexPath.section == 0) {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
return cell1
} else {
let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "SummaryCell", for: indexPath) as! SummaryCell
return cell2
}
}

Related

How to use two CollectionView in one ViewController?

I am working on an existing project which has a collectionView, right now i want to add another collectionView in this same viewcontroller. Already tried different solutions but can not seem to have any luck. Here is the existing code for collectionview:
func numberOfSections(in collectionView: UICollectionView) -> Int {
if homeList.last?.catList.isEmpty ?? false{
return homeList.count - 1
}
return self.homeList.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == homeList.count - 1{
return 2
}
return homeList[section].catList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == homeList.count - 1{
let doctorsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "doctorCell", for: indexPath) as! DoctorsCVC
doctorsCell.docDelegate = self
doctorsCell.docList = homeList[indexPath.section].catList as? [Doctor] ?? []
delayOnMain(0.1){
doctorsCell.docCollectionView.reloadData()
}
return doctorsCell
}
else{
let productsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "productCell", for: indexPath) as! ProductCVC
productsCell.setData(homeList[indexPath.section].catList[indexPath.row])
productsCell.fivePercentView.layer.cornerRadius = 5
return productsCell
}
}
And here is my new code for collectionView:
#IBOutlet var collectionView2: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.img.image = arrData[indexPath.row].image
return cell
}
Can someone help me to merge this code!
What I think is a clearer method is to use a second collectionViewController and a custom container view controller.
That way, the differentiation in the delegate methods is no longer needed.
You can't use two same collectionView delegate methods (eg -cellForItemAt ) methods in same view controller. So you have to check the collection view inside every collectionView delegate methods.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionView2 {
return arrData.count
} else {
if section == homeList.count - 1 {
return 2
}
return homeList[section].catList.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionView2 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.img.image = arrData[indexPath.row].image
return cell
}else{
if indexPath.section == homeList.count - 1{
let doctorsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "doctorCell", for: indexPath) as! DoctorsCVC
doctorsCell.docDelegate = self
doctorsCell.docList = homeList[indexPath.section].catList as? [Doctor] ?? []
delayOnMain(0.1){
doctorsCell.docCollectionView.reloadData()
}
return doctorsCell
}
else{
let productsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "productCell", for: indexPath) as! ProductCVC
productsCell.setData(homeList[indexPath.section].catList[indexPath.row])
productsCell.fivePercentView.layer.cornerRadius = 5
return productsCell
}
}
}

How to call the indexPath.row of a UITableViewCell with a UICollectionView embedded within

Currently, I have a UITableView with a UICollectionView embedded in it. I have 3 arrays of information and I want each array to correspond to a UICollectionView, and therefore a UITableViewCell.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CookieCell", for: indexPath) as? MenuCollectionViewCell
cell?.fullView.layer.borderColor = UIColor.black.cgColor
cell?.labelView.layer.borderColor = UIColor.black.cgColor
cell?.fullView.layer.borderWidth = 0.3
cell?.labelView.layer.borderWidth = 0.3
return cell!
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
}
Where each of the return cell? is, I want to do something like:
if indexPathOfTableView.row == 0 {
//designated parameters
}
else if indexPathOfTableView.row == 1 {
//designated parameters
}
else {
//designated parameters
}
How would I do this?
Hello #helloworld12345
from your question I got the idea that you want to collectionview in tableviewcell
may be below code will help you.
first in you viewController or tableviewcontroller,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
//send indexPath of this cell
let cell = tblView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! tableViewCell
//Pass your array which you want to show in collectionViewCell and then reload collection view
cell.clnView.reloadData()
return cell
}
In your tableViewCell swift file:
class tableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
{
#IBOutlet weak var clnView: UICollectionView!
//after awakenib method write below code
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 4 //pass your array count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
let flowayout = collectionViewLayout as? UICollectionViewFlowLayout
let space: CGFloat = (flowayout?.minimumInteritemSpacing ?? 0.0) + (flowayout?.sectionInset.left ?? 0.0) + (flowayout?.sectionInset.right ?? 0.0)
let size:CGFloat = (self.clnView.frame.size.width - space) / 2.0 //By this you can show two cell in one screen
return CGSize(width: size + 60, height: (size + 200))
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "clnViewCell", for: indexPath) as! clnViewCell
// do your stuff with your
return cell
}
}

reuse UITableViewCell with diferent data

I have 2 arrays with different data
var array : [String] = ["getMeals", "getMeasure", "getWorkouts"]
var array2 : [String] = ["getStep", "getStep", "getStep"]
I am trying to retrieve the images from arrays, but in different collection cells.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
cell.collectionImage.image = UIImage(named: array[indexPath.row])
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
cell.collectionImage.image = UIImage(named: array2[indexPath.row])
return cell
}
}
I need to create another UICollectionViewCell or I can use the current cell?
you can use the same cell, with this code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
if indexPath.section == 0{
cell.collectionImage.image = UIImage(named: array[indexPath.row])
}else{
cell.collectionImage.image = UIImage(named: array2[indexPath.row])
}
return cell
}
You need 1 array like
let array = [["getMeals", "getMeasure", "getWorkouts"],["getStep", "getStep", "getStep"]]
func numberOfSections(in collectionView: UICollectionView) -> Int {
return array.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return array[section].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
cell.collectionImage.image = UIImage(named: array[indexPath.section][indexPath.row])
return cell
}

UICollectionView in UICollectionView reloadData on AppleTV

I am developing appleTV application.
I have a UICollectionView inside a UICollectionView cell.
When the data is updated, the CollectionView placed in the ViewController is reloadData, and at the same time, the CollectionView in the CollectionView is also reloadData.
Then focus does not return to the original position in CollectionView.
The CollectionView placed in the ViewController is canFocusItemAt false.
What should I do?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView === self.collectionView {
return 10
} else {
return 10
}
}
func collectionView(_ collectionView: UICollectionView, canFocusItemAt indexPath: IndexPath) -> Bool {
if collectionView === self.collectionView {
return false
} else {
return true
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView === self.collectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "aaaa", for: indexPath)
if let collectionView = cell.viewWithTag(20) as? UICollectionView {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.reloadData()
}
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "bbbb", for: indexPath)
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.collectionView.reloadData()
}

collectionView cell width not changing for different nib

I have a collection view which is nested inside of a table view cell. The first cell in the collection view is a button which allows users to create a new list. Its width is smaller than that of the main lists cells. I recently changed the code around so that the collectionView delegate and dataSource methods are in the tableViewController instead of the table view cell, however now the first cells width is not changing as it did before moving the code. This picture shows:
If I press into the blank space it is registering that I clicked the plus cell.
The code for all the collectionView delegate and dataSource methods:
extension ProfileTableViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("the media: \(usersLists.count)")
return usersLists.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "addNewListCell", for: indexPath) as! addNewListCell
cell.currentUser = currentUser
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! userListsCell
cell.layer.applySketchShadow()
cell.layer.cornerRadius = 20
cell.layer.masksToBounds = false
cell.currentUser = currentUser
cell.media = usersLists[indexPath.item-1]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
if indexPath.item == 0 {
let size = CGSize(width: 80, height: 158)
return size
}else{
let size = CGSize(width: 158, height: 158)
return size
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == 0 {
//button
self.addListDelegate?.addNewItem()
}
}
I tested if changing any values in the size in sizeForItemAt would change the cell size and nothing changes in any cells
the table view methods which are in the ProfileTableViewController class and not the extension:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "profileCell", for: indexPath) as! profileCell
cell.selectionStyle = .none
return cell
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? profileCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: indexPath.row) //this line sets the collectionView delegate and datasouce so that I can have all of the collectionView methods in this class
}
and this is the code inside of the tableViewCell
protocol addListCollectionDelegate: class {
func addNewItem()
}
class profileCell: UITableViewCell, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.register(UINib(nibName: "usersLists", bundle: nil), forCellWithReuseIdentifier: "listCell")
collectionView.register(UINib(nibName: "newListCell", bundle: nil), forCellWithReuseIdentifier: "addNewListCell")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setCollectionViewDataSourceDelegate
<D: UICollectionViewDataSource & UICollectionViewDelegate>
(dataSourceDelegate: D, forRow row: Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.reloadData()
}
}
Does anyone know how to change the width of the first cell since sizeForItemAt is not changing the size? Thanks
You forgot to add this protocol: UICollectionViewDelegateFlowLayout
It is required when you want to return custom size for an item.
Also improve your code like below:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "addNewListCell", for: indexPath) as! addNewListCell
cell.currentUser = currentUser
return cell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! userListsCell
cell.layer.applySketchShadow() // Write this line in cell class
cell.layer.cornerRadius = 20 // Write this line in cell class
cell.layer.masksToBounds = false // Write this line in cell class
cell.currentUser = currentUser
cell.media = usersLists[indexPath.item - 1]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
return indexPath.item == 0 ? CGSize(width: 80, height: 158) : CGSize(width: 158, height: 158)
}
Try to use UICollectionViewDelegateFlowLayout method. In Xcode 11 or later, you need to set Estimate Size to none from Xib.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 170
let collectionViewSize = advertCollectionView.frame.size.width - padding
return CGSize(width: collectionViewSize/2, height: collectionViewSize/2)
}

Resources