简体   繁体   中英

How to change image of imageview in tableview custom cell with pagination.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM