UICollectionView keeps crashing unless i set indexpath.items = 1 - swift

Hi I have two codes for someone reason 1 works while the other doesn't can someone please explain why? The first function works, while the second doesn't. I'm trying to generate one cell as the type PayNowCell and every cell after that as the CheckOutCell type. However, it will only allow me to put the first cell as a CheckOutCell, the second as a PayNowCell, and every following cell as a CheckOutCell. Thanks!!! Error is index is out of bounds. And it points to this line
cell.item = checkout[indexPath.item].
Essentially i have a dynamic array checkout[] and im just trying to insert a description cell called paynow ontop of each checkoutcell while the checkout[] grows and shrinks
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
cell.item = checkout[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
cell.item = checkout[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (checkout.count + 1) //init number of cells
}

Try this array for manage your collection view
var array = [0,[]]
then add
array[1] = [your array for index 1]
You can add the section for manage multi-cell inside your collection view:-
func numberOfSections(in collectionView: UICollectionView) -> Int{
return (array[section] as AnyObject).count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return array[1].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
let checkout = array[1] // pass here array
guard checkout.count != 0 else {
return cell
}
cell.item = checkout[indexPath.item]
return cell
}
}

Related

How to show AdCell for every three cells of table view in swift

I have to show Adcell for every three cells after. for that I have taken two prototype cells and designed adcell in one and normal cell in other
code: with my code only after first three rows AdCell showing and lost 3rd row from JobsCell from 4th row data showing
how to show Adcell for every cells and without losing JobsCell data. please guide
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return categoryData?.result?.categoryData?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var returnCell: UITableViewCell!
if indexPath.row == 3 {
returnCell = tableView.dequeueReusableCell(withIdentifier: "AdCell", for: indexPath) as! AdCell
}
else {
returnCell = tableView.dequeueReusableCell(withIdentifier: "JobsCell", for: indexPath) as! JobsCell
returnCell.selectionStyle = .none
}
return returnCell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
var count = categoryData?.result?.categoryData?.count ?? 0
return count + count / 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var returnCell: UITableViewCell!
if indexPath.row % 3 == 0 && indexPath.row != 0 {
returnCell = tableView.dequeueReusableCell(withIdentifier: "AdCell", for: indexPath) as! AdCell
}
else {
returnCell = tableView.dequeueReusableCell(withIdentifier: "JobsCell", for: indexPath) as! JobsCell
returnCell.selectionStyle = .none
}
return returnCell
}
The first problem: in your example func(numberOfItemsInSection) returns less rows than need. Therefore, to begin with, adding the missing cells.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let n = categoryData?.result?.categoryData?.count ?? 0
//for example here 10 jobs
//3j 1a 3j 1a 3j 1a 1j(last) Here 3ads
//10/3 = 3(and 1)
//so will 11/3=3(2), then 12/3=4(0)
//So generic formula: num = j + j/3
let num = n + n/3 //n is Int so division rounds the number down
return num
}
Second problem: when adding an extra cell in indexPath, it gonna lost fourth job if using data[indexPath.row].
So it possible to create variable like "jumpDownNumber". It will save the step to the skipped indexPath.row number.
var jumpDownNumber = 0 //and reload it before tableView.reloadData()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var returnCell: UITableViewCell!
//after 3 jobCell is every fourth AD cell
if (indexPath.row+1) % 4 == 0 {
returnCell = tableView.dequeueReusableCell(withIdentifier: "AdCell", for: indexPath) as! AdCell
jumpDownNumber += 1
} else {
returnCell = tableView.dequeueReusableCell(withIdentifier: "JobsCell", for: indexPath) as! JobsCell
//here you can use data[indexPath.row-jumpDownNumber]
returnCell.selectionStyle = .none
}
return returnCell
}

CollectionView First And Last Cell remains selected

i am using a collectionView which is selectable, and when a user selects the first then the last cell both cells remain selected for some reason idk why.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
if (collectionView == self.categoryCollectionView)
{
let cell = collectionView.cellForItem(at: indexPath) as? ChannelsCategoryCell
cell?.triangleIndicatorView.isHidden = false
cell?.categoryLabel.textColor = UIColor.init(named: "ActiveSymbol")
loadChannelList()
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath)
{
if (collectionView == self.categoryCollectionView)
{
let cell = collectionView.cellForItem(at: indexPath) as? ChannelsCategoryCell
cell?.triangleIndicatorView.isHidden = true
cell?.categoryLabel.textColor = UIColor.init(named: "InactiveCategoryText")
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! CollectionViewCell
if selectedIndex == indexPath.item {
cell.backgroundColor = .blue
} else {
cell.backgroundColor = .clear
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.item
collectionView.reloadData()
}

change tableview cell content on collection view cell selection

I have a tableView and collectionView in one view controller.
in tableView I have title description and in collectionView I have lable .
I want on collectionView label selection tableView content should change .
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Bookmark.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionViewBookmark.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BookMarkCollectionViewCell
cell.lblTitle.text = Bookmark[indexPath.row]
cell.backgroundColor = UIColor.white
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionViewBookmark.cellForItem(at: indexPath)
cell?.backgroundColor = UIColor.blue
self.selectedIndexPath = indexPath
//
let newsDict = arrNewsData[indexPath.row]
if (indexPath.row == 1)
{
let cell1 = tableViewBookMark.cellForRow(at: indexPath) as! BookMarkFirstTableViewCell
cell1.lblTitle.text = newsDict["title"] as! String
tableViewBookMark.reloadData()
}
tableViewBookMark.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableViewBookMark.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! BookMarkFirstTableViewCell
let dict = arrNewsData[indexPath.row]
cell.lblTitle.text = dict["title"] as! String
// cell.imgBookMark.image = dict["image_url"]
let url = URL(string: dict["image_url"] as! String)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if data != nil{
DispatchQueue.main.async {
let image = UIImage(data: data!)
cell.imgBookMark.image = image
}
}
}.resume()
return cell
}
See my inline comments.
var tempCell: BookMarkFirstTableViewCell?
//Inside cellForRowAt indexPath
tempCell = cell
//Inside (collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
tempCell.lblTitle.text = newsDict["title"] as! String
You're reloading the tableView after updating the values in the cell,
tableViewBookMark.reloadData()
This will trigger the data source function including cellForRowAt, so you will lose your updated values a solution to this is to have a global variable in the UIViewController and check its values inside the cellForRowAt and update it in the collectionView DidSelect .
Extra tip: you don't need to reload all the tableView for a single change you can use
tableView.reloadRows(at: [indexPath], with: .top)
to reload only number of selected cells in the tableView

Divide the number of cell between two prototypes

as I am beginner I have a problem that may not be so pro to ask.
I have two prototype collection view cell in my app, let's call them Cell1 and Cell2, they both are in a same section.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as? customCell {
return cell
} else if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as? customCell {
return cell
}
return UICollectionViewCell()
}
My problems starts from here:
in numberOfItemsInSection, I want to say for example draw 3 cell from prototype Cell1 and 5 cell from Cell2.
I don't know how I divide the number of cell between two prototypes, could anyone help me on that?
You can try
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 8
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (0...2).contains(indexPath.item) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as! customCell {
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as? customCell {
return cell
}
}
you have several options for this. If you know how many cells you will be having, lets say 8 you can just do a simple switch.
switch indexPath.item {
case 0,1,2,3:
let cell = .....
return cell
case 4,5,6,7:
let cell2 = ....
return cell
default:
let cell = ...
return cell
}
you can also do a modulo approach, which will give you cell1 for even item numbers and cell2 for uneven.
Without knowing your intentions directly, I can give you only a broad answer.

Passing data between multiple UICollectionViewCell

I got a collection view with 2 different sections. I want to tap a cell in one of the sections and pass the text in that cell to a text view, which is in a separate cell in its own section.
This is what I tried so far, but nothing happened. I am trying to send the notes data to another cell. I can print the data when the cell is tapped.
Updated: This is the cell with the text view that I want to pass the selected cell data to.
// cell that I am trying to passing data to
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = myCollectionView.dequeueReusableCell(withReuseIdentifier: "notesView", for: indexPath) as! TestViewCollectionViewCell
cell.myTextView.text = .....
return cell
}
// Cell that I am passing data from
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.section == 0 {
// Cell that I want to send data to
let cell = myCollectionView.dequeueReusableCell(withReuseIdentifier: "notesView", for: indexPath) as! TestViewCollectionViewCell
let myNotes = notes[indexPath.row]
cell.myTextView.text = myNotes.textView
}
}
Here is the way you can correct that:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.section == 0 {
//First get your selected cell
if let cell = collectionView.cellForItem(at: indexPath) as? TestViewCollectionViewCell {
//Now get selected cell text here
//update your section two array with new values
//Reload your collection view.
} else {
// Error indexPath is not on screen: this should never happen.
}
}
}