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()
}
Related
[ I want to use two custom cells in one UICollectionView and this is by far I have been trying and I am stuck. Cell one for first and row and cell two of the second row and again cell one for 3rd, you get the point.
here is the code ]
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var CV: UICollectionView!
let labelArray = ["one", "two", "three", "four"]
let imageArray = [UIImage(named: "one"), UIImage(named: "two"), UIImage(named: "three"), UIImage(named: "four") ]
override func viewDidLoad() {
super.viewDidLoad()
CV.delegate = self
CV.dataSource = self
CV.reloadData()
// let nibCellOne = UINib(nibName: "CVCellOne", bundle: nil)
// let nibCellTwo = UINib(nibName: "CVCellTwo", bundle: nil)
// CV.register(nibCellOne, forCellWithReuseIdentifier: "CVCellOne")
// CV.register(nibCellTwo, forCellWithReuseIdentifier: "CVCellTwo")
CV.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CVCellOne")
CV.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CVCellTwo")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCellOne", for: indexPath) as! CollectionViewCell
cell1.cellOneLabel.text = labelArray[indexPath.row]
return cell1
}
else if indexPath.section == 1 {
let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCellTwo", for: indexPath) as! CollectionViewCell
cell2.cellTwoLabel.text = labelArray[indexPath.row]
return cell2
} else if indexPath.section == 2 {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCellOne", for: indexPath) as! CollectionViewCell
cell1.cellOneImage.image = imageArray[indexPath.row]
cell1.cellOneLabel.text = labelArray[indexPath.row]
return cell1
} else {
let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCellTwo", for: indexPath) as! CollectionViewCell
cell2.cellTwoImage.image = imageArray[indexPath.row]
cell2.cellTwoLabel.text = labelArray[indexPath.row]
return cell2
}
}
}
This is the customCell xib file
If what you need is every even row to use Cell1, and every odd row to use Cell2, then don't check for the specific row, check for the remainder when you divide by 2 (modulus) indexPath.item % 2 == 0
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item % 2 == 0 {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCellOne", for: indexPath) as! CollectionViewCell
cell1.cellOneLabel.text = labelArray[indexPath.row]
return cell1
}
} else {
let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCellTwo", for: indexPath) as! CollectionViewCell
cell2.cellTwoLabel.text = labelArray[indexPath.row]
return cell1
}
}
}
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()
}
based on the screen shot, I will have a big collectionview to contain few cells (with colors). All cell will display only one time in the view except for the green one.The green one will display an array of users.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: topfeatureCellIndent, for: indexPath) as! topFeatureCell
//configure if needed
return cell
}else if indexPath.item == 1{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: userCellIdent, for: indexPath) as! featureUserContainerViewCell
cell.featureUsers = featureUser
cell.selectUserdelegate = self
return cell
}else if indexPath.item == 2{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ticketLabelIdent, for: indexPath) as! ticketLabelCell
return cell
} else if indexPath.item == 3{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: whosgoingIdent, for: indexPath) as! whoGoingCell
cell.config(withTimer: timeleft)
return cell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: allUserCellIdent, for: indexPath) as! allUserCell
let index = indexPath.item - 4
let user = allPartyUserArr![index]
cell.config(withUser: user)
return cell
The way I need to display the last cell is by implement the code above but I think its not correct, because what if I want to add in other cells after displaying all the cells, is there any better way to dequeue the cell properly?
I would suggest you to use 2 Sections in UICollectionView.
keep all the one-time visible cells in section 0 and the cells which will represent array for users in section 1
This is how you can set number of sections
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
To set Header of each section you can implement below functions and set any size for your header. CGSizeMake(0, 0) will hide the Header
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width : 0, height : 0) // Header size
}
then number of items in each section
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 4
}
else {
users.count
}
//return (section == 0) ? 4 : users.count
}
to display cell
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
// Based on Your implementation
if indexPath.item == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: topfeatureCellIndent, for: indexPath) as! topFeatureCell
//configure if needed
return cell
}else if indexPath.item == 1{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: userCellIdent, for: indexPath) as! featureUserContainerViewCell
cell.featureUsers = featureUser
cell.selectUserdelegate = self
return cell
}else if indexPath.item == 2{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ticketLabelIdent, for: indexPath) as! ticketLabelCell
return cell
} else if indexPath.item == 3{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: whosgoingIdent, for: indexPath) as! whoGoingCell
cell.config(withTimer: timeleft)
return cell
} else {
return UICollectionViewCell()
}
}else{
//make sure the identifier of your cell for second section
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: allUserCellIdent, for: indexPath) as! allUserCell
// populate your user cell here
return cell
}
}
You can set the number of sections in CollectionView like this :
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 5
}
Set number of items in each section :
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
return 1
default:
return 3
}
}
Number of items you can set according to the section.
and for cells in each section :
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.section {
case 0:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: topfeatureCellIndent, for: indexPath) as! topFeatureCell
//configure if needed
return cell
case 1:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: userCellIdent, for: indexPath) as! featureUserContainerViewCell
cell.featureUsers = featureUser
cell.selectUserdelegate = self
return cell
case 2:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ticketLabelIdent, for: indexPath) as! ticketLabelCell
return cell
case 3:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: topfeatureCellIndent, for: indexPath) as! topFeatureCell
//configure if needed
return cell
case 4:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: whosgoingIdent, for: indexPath) as! whoGoingCell
cell.config(withTimer: timeleft)
return cell
default:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: allUserCellIdent, for: indexPath) as! allUserCell
let index = indexPath.item - 4
let user = allPartyUserArr![index]
cell.config(withUser: user)
return cell
}
}
Hope this helps or else you can google for more better tutorials and solutions.
I have a horizontally scrollable UICollectionView with three cells each of which are different subclasses of UICollectionViewCell. Each one of these cells contains a UITableView.
Inside of the first two cells, my table view cells are the same subclasses of UITableViewCell and have just a UIImageView. I use it to set its backgroundColor. Inside of the third cell, my table view's cells are different subclasses of UITableViewCell than in the previous two. They have both a UILabel and a UIImageView. The label has some dummy text, and I set imageView's backgroundColor to some color, again.
In order to follow MVC pattern, I use my UIViewController as a data source and a delegate for both collection view, and table view. Here is the code of UIViewController:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let collectionViewCellId = "collectionViewCell"
let tableViewCellId = "tableViewCell"
let collectionViewCellId2 = "collectionViewCellId2"
let collectionViewCellId3 = "collectionViewCellId3"
let tableViewCellDif = "tableViewCellDif"
var collectionViewIndex: Int?
#IBOutlet weak var collectionView: UICollectionView! {
didSet {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isPagingEnabled = true
}
}
//MARK: UITableViewDataSource
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let colors: [UIColor] = [.red, .green, .purple, .orange, .blue]
let colors2: [UIColor] = [.blue, .brown, .yellow, .magenta, .cyan]
if collectionViewIndex == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellId, for: indexPath) as! TableViewCell
cell.colorForImageView = colors[indexPath.row]
return cell
} else
if collectionViewIndex == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellId, for: indexPath) as! TableViewCell
cell.colorForImageView = colors2[indexPath.row]
return cell
} else
if collectionViewIndex == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellDif, for: indexPath) as! TableViewCellDifferent
cell.colorForImageView = colors2[indexPath.row]
return cell
} else {
return UITableViewCell()
}
}
}
//MARK: UICollectionViewDataSource
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let identifier: String
if indexPath.item == 0 {
identifier = collectionViewCellId
} else if indexPath.item == 1 {
identifier = collectionViewCellId2
} else if indexPath.item == 2 {
identifier = collectionViewCellId3
} else {
identifier = ""
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
return cell
}
}
//MARK: UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.item == 0 {
let cell = cell as! CollectionViewCell
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 0
}
if indexPath.item == 1 {
let cell = cell as! CollectionViewCell2
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 1
}
if indexPath.item == 2 {
let cell = cell as! CollectionViewCell3
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 2
print (collectionViewIndex)
}
}
}
//MARK: UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let layout = collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
}
}
As I stated in a title of the question, nothing happens on a background thread. I, basically, only set the backgroundColor of table view's cells.
The problem is that inside the collection view's third cell (and only inside of there), my table view dequeues its cells only after a minor scroll or tap happens. Here is how it looks like:
I can't figure out why this happens. Maybe, this happens because inside of the third cell of the collection view, my table view's cells are instances of different subclass than inside of the first two?
EDITED
I could solve the problem by reloading the table view before before showing the collection view's each cell but I'm not sure that this is the most efficient solution. Here is the code:
//MARK: UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.item == 0 {
let cell = cell as! CollectionViewCell
cell.tableView.dataSource = self
cell.tableView.delegate = self
cell.tableView.reloadData()
collectionViewIndex = 0
}
if indexPath.item == 1 {
let cell = cell as! CollectionViewCell2
cell.tableView.dataSource = self
cell.tableView.delegate = self
cell.tableView.reloadData()
collectionViewIndex = 1
}
if indexPath.item == 2 {
let cell = cell as! CollectionViewCell3
cell.tableView.dataSource = self
cell.tableView.delegate = self
cell.tableView.reloadData()
collectionViewIndex = 2
}
}
}
If you know a better way, I would appreciate your help.
I gave this a try, and saw the same results. So, I moved your collection view cell "setup" code from willDisplay cell: to cellForItemAt and it fixed the problem.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellId, for: indexPath) as! CollectionViewCell
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 0
return cell
}
if indexPath.item == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellId2, for: indexPath) as! CollectionViewCell2
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 1
return cell
}
// if we get here, indexPath.item must equal 2
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellId3, for: indexPath) as! CollectionViewCell3
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 2
return cell
}
Now, since you're not showing your code for your tableview cells, it's possible there might be another issue, but this worked for me:
class TableViewCell: UITableViewCell {
#IBOutlet var theImageView: UIImageView!
var colorForImageView: UIColor = UIColor.gray {
didSet {
self.theImageView.backgroundColor = colorForImageView
}
}
}
You can try to dequeue CollectionViewCell or TableViewCell explicitly on the main thread
DispatchQueue.main.async {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
}
or
DispatchQueue.main.async {
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellDif, for: indexPath) as! TableViewCellDifferent
cell.colorForImageView = colors2[indexPath.row]
}
It could help to wake up the main thread
But in general, it would be much easier if a data source for the table view was inside collection view cell
I have a UICollectionView which uses custom xib file for it's cells. In the cell I have an ImageView for check box. I want to change the image of the `ImageView1 when it was taped. I tried the following code snippet but, it's not working for me
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
if show_delete == true {
cell.img_delete.image = UIImage(named: "checked")
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
// Configure the cell
let data = valves_[indexPath.row]
cell.v_name.text = data
if show_delete == true {
cell.img_delete.isHidden = false
} else if show_delete == false {
cell.img_delete.isHidden = true
}
return cell
}
In this code I've tried to change the image of ImageView in didSelectItemAt.
My custom xib file is as following.
Please suggest a way to make it work. Thanks.
For these kind of problems, it is always better to keep an array which contains whether an item at a given indexpath is checked or not.
var checkArray: [Bool] = [Bool](repeating: false, count: numberOfRowsInCollectionView)
// this should be the same size as number of items in collection view
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
checkArray[indexPath.row] = !checkArray[indexPath.row] // if it's true, make it false and vice versa logic
collectionView.reloadItems(at: [indexPath])
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
// Configure the cell
let data = valves_[indexPath.row]
cell.v_name.text = data
if show_delete == true {
cell.img_delete.isHidden = false
} else if show_delete == false {
cell.img_delete.isHidden = true
}
if checkArray[indexPath.row] {
cell.img_delete.image = //image for check
}else {
cell.img_delete.image = //image for no check
}
return cell
}
Finally I solved it by the following code.
var checkArray = [Int]()
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if show_delete == true {
if checkArray.contains(indexPath.row) {
let index = checkArray.index(of: indexPath.row)
checkArray.remove(at: index!)
collectionView.reloadItems(at: [indexPath])
} else {
checkArray.append(indexPath.row)
collectionView.reloadItems(at: [indexPath])
}
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
// Configure the cell
let data = valves_[indexPath.row]
cell.v_name.text = data
if show_delete == true {
cell.img_delete.isHidden = false
} else if show_delete == false {
cell.img_delete.isHidden = true
}
if checkArray.contains(indexPath.row) {
cell.img_delete.image = UIImage(named: "checked_n")
} else {
cell.img_delete.image = UIImage(named: "unchecked")
}
return cell
}
I put taped element indexes in an array and reloaded the items at indexpath. if the array contains the reloaded index then it displays the check mark, if not it removes the check mark.