Load multiple UICollectionView in UITableView in view controller Swift - ios

I am building an iOS application where there are 4 different designs of the UICollectionViewn
in UITableView.
UICollectionViewCell Class Name are : DealCollectionViewCell, FilterCollectionViewCell, ComboCollectionViewCell, BusinessCollectionViewCell
UITableViewCell Class Name are : DealTableViewCell, BusinessTableViewCell, FilterTableViewCell, ComboTableViewCell
Below is UIViewController class code (Class Name HomeViewControllerr)
class extend
UIViewController, UITableViewDelegate, UITableViewDataSource, UICollectionViewDelegate, UICollectionViewDataSource
For UITableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier: "DealTableViewCellId") as! DealTableViewCell
return cell
}
else if indexPath.row == 1
{
let cell = tableView.dequeueReusableCell(withIdentifier: "FilterTableViewCellId") as! FilterTableViewCell
return cell
}
else if indexPath.row == 2
{
let cell = tableView.dequeueReusableCell(withIdentifier: "ComboTableViewCellId") as! ComboTableViewCell
return cell
}
else
{
let cell = tableView.dequeueReusableCell(withIdentifier: "BusinessTableViewCellId") as! BusinessTableViewCell
return cell
}
}
  For UICollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return dealImageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DealCollectionViewCellId", for: indexPath) as? DealCollectionViewCell
return cell!
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "ProductViewControllerId") as! ProductViewController
self.present(nextViewController, animated:true, completion:nil)
//self.navigationController?.pushViewController(nextViewController, animated: true)
}
Now I want to add multiple UICollectionViewCell in cellForItemAt function. Like below (This I had done when I was not using UITableView)
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == dealCollectionView)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DealCollectionViewCellId", for: indexPath) as? DealCollectionViewCell
return cell!
}
else if (collectionView == comboCollectionView)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ComboColllectionViewCellId", for: indexPath) as? ComboColllectionViewCell
return cell!
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BusinessCollectionViewCell", for: indexPath) as? BusinessCollectionViewCell
return cell!
}
}

extension HomeViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DealTableViewCell", for: indexPath) as! DealTableViewCell
cell.DealCollectionView.dataSource = self
cell.DealCollectionView.delegate = self
cell.DealCollectionView.tag = 10101
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "BusinessTableViewCell", for: indexPath) as! BusinessTableViewCell
cell.BusinessCollectionView.dataSource = self
cell.BusinessCollectionView.delegate = self
cell.BusinessCollectionView.tag = 10102
return cell
} else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "FilterTableViewCell", for: indexPath) as! FilterTableViewCell
cell.FilterCollectionView.dataSource = self
cell.FilterCollectionView.delegate = self
cell.FilterCollectionView.tag = 10103
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "ComboTableViewCell", for: indexPath) as! ComboTableViewCell
cell.ComboCollectionView.dataSource = self
cell.ComboCollectionView.delegate = self
cell.ComboCollectionView.tag = 10104
return cell
}
}
}
Add the collection view to each tableview cell and set delegate in tableview cell
extension HomeViewController : UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 10101 {
return 3
} else if collectionView.tag == 10102 {
return 3
} else if collectionView.tag == 10103 {
return 3
} else if collectionView.tag == 10104 {
return 3
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 10101 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "DealCollectionViewCell", for: indexPath) as! DealCollectionViewCell
return cell
} else if collectionView.tag == 10102 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "BusinessCollectionViewCell", for: indexPath) as! BusinessCollectionViewCell
return cell
} else if collectionView.tag == 10103 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "FilterCollectionViewCell", for: indexPath) as! FilterCollectionViewCell
return cell
} else if collectionView.tag == 10104 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "ComboCollectionViewCell", for: indexPath) as! ComboCollectionViewCell
return cell
}
return UICollectionViewCell()
}
}
For reload the collectionView in use
if let cell = self.tableView.cellForRow(at: IndexPath(row: i, section: 0)) as? tableViewCell {
cell.collectionView.reloadData()
}

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
}
}
}

UITableView inside a UICollectionView: can't set value

I have a UICollectionView with 4 UICollectionViewCells. Each cell contains a UITableView with a varying number of cells.
I have an array from which I need to pass a value (depending on the indexPath) into the cell. My problem is that it always gives me nil when I try to do this.
So for example I have this array:
let arrayOfStrings = ["test1", "test2", "test3", "test4"]
I have this code in my collection view's cellForItemAt method:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "testCollectionViewCell", for: indexPath) as! TestCollectionViewCell
cell.myString = arrayOfStrings[indexPath.row]
cell.label.text = "This text is set."
return cell
}
The cell's label is set properly, but when I try to print myString in the cell's table view's cellForRowAt method it always returns nil.
I need the string because I plan to manipulate the table views depending on the string passed in.
So why is this happening and what can be done?
You can try like this
extension HomeViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DealTableViewCell", for: indexPath) as! DealTableViewCell
cell.DealCollectionView.dataSource = self
cell.DealCollectionView.delegate = self
cell.DealCollectionView.tag = 10101
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "BusinessTableViewCell", for: indexPath) as! BusinessTableViewCell
cell.BusinessCollectionView.dataSource = self
cell.BusinessCollectionView.delegate = self
cell.BusinessCollectionView.tag = 10102
return cell
} else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "FilterTableViewCell", for: indexPath) as! FilterTableViewCell
cell.FilterCollectionView.dataSource = self
cell.FilterCollectionView.delegate = self
cell.FilterCollectionView.tag = 10103
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "ComboTableViewCell", for: indexPath) as! ComboTableViewCell
cell.ComboCollectionView.dataSource = self
cell.ComboCollectionView.delegate = self
cell.ComboCollectionView.tag = 10104
return cell
}
}
}
Add the collection view to each tableview cell and set delegate in tableview cell
extension HomeViewController : UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 10101 {
return 3
} else if collectionView.tag == 10102 {
return 3
} else if collectionView.tag == 10103 {
return 3
} else if collectionView.tag == 10104 {
return 3
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 10101 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "DealCollectionViewCell", for: indexPath) as! DealCollectionViewCell
return cell
} else if collectionView.tag == 10102 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "BusinessCollectionViewCell", for: indexPath) as! BusinessCollectionViewCell
return cell
} else if collectionView.tag == 10103 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "FilterCollectionViewCell", for: indexPath) as! FilterCollectionViewCell
return cell
} else if collectionView.tag == 10104 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "ComboCollectionViewCell", for: indexPath) as! ComboCollectionViewCell
return cell
}
return UICollectionViewCell()
}
}
For reload the collectionView in use
if let cell = self.tableView.cellForRow(at: IndexPath(row: i, section: 0)) as?
tableViewCell {
cell.collectionView.reloadData()
}

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
}

how to display coreData on a collection view cell (swift4)

My code below would work if it was displayed on a label. But in this function I am getting the error message Missing return in a function expected to return 'UICollectionViewCell'. Putting the return cell in the for loop does not work.
import UIKit
class collectionVIEW: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var users = [User]()
#IBOutlet var theIssues: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// users = cdHandler.fetchObject()!
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return users.count
}
func getDefaultCell() -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! whyCollectionViewCell
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cdHandler.fetchObject() != nil {
users = cdHandler.fetchObject()!
for c in users {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! whyCollectionViewCell
cell.general.text = "\((cell.general.text)!)+\((c.userName)!)"
return cell
}
} else {
return getDefaultCell()
}
}
}
cellForItemAt method expects to return UICollectionViewCell in all cases. In the else condition, return a default cell as below:-
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cdHandler.fetchObject() != nil {
users = cdHandler.fetchObject()!
for c in users {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! whyCollectionViewCell
cell.general.text = "\((cell.general.text)!)+\((c.userName)!)"
return cell
}
}else{
return getDefaultCell()
}
Note:-Register collection view with identifier defaultCcell
func getDefaultCell() -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "defaultCcell", for: indexPath) as! UICollectionViewCell
return cell
}

Adding new Item to CollectionView programmatically, via the last Item

I'm facing an issue with CollectionView, I want to see a collection of images and have an add button as the last item so first of all I've made an array of NSData as I'm gonna save those images to Core Data
var photoArray = [NSData]()
then I implement UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == photoArray.count + 1 {
present(imagePicker, animated: true, completion: nil)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photoArray.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoItem", for: indexPath) as? PhotoCell else {return UICollectionViewCell()}
cell.btn.tag = indexPath.item
if indexPath.item == photoArray.count + 1 {
cell.thumImage.image = UIImage(named: "add_button")
cell.btn.isHidden = true
print("first")
return cell
} else {
let img = photoArray[indexPath.item]
cell.configureAddingImage(img: img)
print("second")
return cell
}
}
Actually I'm facing with the problem in "cellForItemAt indexPath" like "fatal error: index is out of range" I tried to make array look like var photoArray: [NSData]! but it caused other problems, please give me any advice or help, thank you!
Index is out of range because items or rows are indexed from 0
Should be like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoItem", for: indexPath) as? PhotoCell else {return UICollectionViewCell()}
cell.btn.tag = indexPath.row
if indexPath.row == photoArray.count {
cell.thumImage.image = UIImage(named: "add_button")
cell.btn.isHidden = true
print("first")
return cell
} else {
let img = photoArray[indexPath.row]
cell.configureAddingImage(img: img)
print("second")
return cell
}
}

Resources