I am using a tableview in an app in which I have used pagination. The request is sent to the server and it returns items in batches of size 10. everything is working fine till now. Now I have an imageview in my tableview cells (custom). I want that when the image of that imageview toggles when user taps on it. I tried this thing in the following way:
TableviewController:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell : AdventureTableViewCell = tableView.dequeueReusableCell(withIdentifier: "adventureCell" , for: indexPath) as? AdventureTableViewCell else {
fatalError("The dequeued cell is not an instance of AdventureViewCell.")
}
cell.adventureName.text = adventureList[indexPath.row]
cell.amountLabel.text = "\(adventurePriceList[indexPath.row])$"
cell.favouriteButtonHandler = {()-> Void in
if(cell.favouriteButton.image(for: .normal) == #imageLiteral(resourceName: "UnselectedFavIcon"))
{
cell.favouriteButton.setImage(#imageLiteral(resourceName: "FavSelectedBtnTabBar"), for: .normal)
}
else
{
cell.favouriteButton.setImage(#imageLiteral(resourceName: "UnselectedFavIcon"), for: .normal)
}
}
}
CustomCell:
class AdventureTableViewCell: UITableViewCell {
@IBOutlet weak var adventureName: UILabel!
@IBOutlet weak var adventureImage: UIImageView!
@IBOutlet weak var amountLabel: UILabel!
@IBOutlet weak var favouriteButton: UIButton!
@IBOutlet weak var shareButton: UIButton!
var favouriteButtonHandler:(()-> Void)!
var shareButtonHandler:(()-> Void)!
override func awakeFromNib() {
super.awakeFromNib()
adventureName.lineBreakMode = .byWordWrapping
adventureName.numberOfLines = 0
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
adventureImage.af_cancelImageRequest()
adventureImage.layer.removeAllAnimations()
adventureImage.image = nil
}
@IBAction func favouriteButtonTapped(_ sender: Any) {
self.favouriteButtonHandler()
}
Now the problem which I am facing is that if user taps the first the imageview on any cell it changes its image, but along with that every 4th cell changes it image. For example, if I have tapped imageview of first cell its image is changed but image of cell 5, 9, 13... also get changed.
What is wrong with my code? Did I miss anything? It is some problem with indexPath.row due to pagination, but i don't know what is it exactly and how to solve it. I found a similar question but its accepted solution didn't work for me, so any help would be appreciated.
if you need to toggle image and after scrolling also that should be in last toggle state means you need to use an array to store index position and toggle state by comparing index position and scroll state inside cellfoeRowAtIndex
you can get the last toggle state that is one of the possible way to retain the last toggle index even when you scroll tableview otherwise you will lost your last toggle position
if self.toggleStatusArray[indexPath.row]["toggle"] as! String == "on"{
cell.favouriteButton.setImage(#imageLiteral(resourceName: "FavSelectedBtnTabBar"), for: .normal)
} else {
cell.favouriteButton.setImage(#imageLiteral(resourceName: "UnselectedFavIcon"), for: .normal)
}
cell.favouriteButtonHandler = {()-> Void in
if self.toggleStatusArray[indexPath.row]["toggle"] as! String == "on"{
//Assign Off status to particular index position in toggleStatusArray
} else {
//Assign on status to particular index position in toggleStatusArray
}
}
Hope this will help you
Your code looks OK, I see just one big error.
When u are setting dynamic data (names, images, stuff that changes all the time) use func tableView(UITableView, willDisplay: UITableViewCell, forRowAt: IndexPath)
not cellForRowAt indexPath
.
cellForRowAt indexPath
should be used for static resources, and cell registration.
If u are on iOS 10 + take a look at prefetchDataSource
gonna speed things up a loot, I love it. https://developer.apple.com/documentation/uikit/uitableview/1771763-prefetchdatasource
Small example:
here u register the cell, and set up all the stuff that is common for all the cells in the table view
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "adventureCell" , for: indexPath)
cell.backgroundColor = .red
return cell
}
here adjust all the stuff that is object specific
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.nameLabel.text = model[indexPath.row].name
// also all the specific UI stuff goes here
if model[indexPath.row].age > 3 {
cell.nameLabel.textColor = .green
} else {
cell.nameLabel.textColor = .blue
}
}
You need this because cells get reused, and they have their own lifecycle, so you want to set specific data as late as possible, but you want to set the generic data as less as possible ( most of the stuff you can do once in cell init ).
Cell init is also a great place for generic data, but u can not put everything there
Also, great thing about cell willDisplay
is the that u know actual size of the frame at that point
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.