Button action in custom UITableViewCell affects ot

2020-03-08 05:17发布

问题:

I have a TablewView that has prototype UITableViewCell that has its own class,

Custom UITableViewCell Class

import UIKit

class H_MissingPersonTableViewCell: UITableViewCell {

    @IBOutlet weak var strName: UILabel!
    @IBOutlet weak var imgPerson: UIImageView!
    @IBOutlet weak var Date1: UILabel!
    @IBOutlet weak var Date2: UILabel!
    @IBOutlet weak var MainView: UIView!
    @IBOutlet weak var btnGetUpdates: UIButton!
    @IBOutlet weak var btnComment: UIButton!
    @IBOutlet weak var btnReadMore: UIButton!


    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

The TableView loads perfectly and the dataSource and delegate work fine. However, when I click a BUTTON at IndexPath.row = 0 (zero), and then I scroll down , I would see random(?) or other cells also being highlighted as a result of clicking BUTTON in row 0...

Here is my CellForRowAtIndexPath code:

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        println("called")
        var cell : CustomCell


        cell = tableView.dequeueReusableCellWithIdentifier("CustomCellID", forIndexPath: indexPath) as! CustomCell
        cell.strName.text = self.names[indexPath.row]
        cell.imgPerson.image = UIImage(named: "\(self.persons[indexPath.row])")!

        cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnGetUpdates.layer.borderWidth = 1
        cell.btnGetUpdates.layer.cornerRadius = 5.0


        cell.btnComment.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnComment.layer.borderWidth = 1
        cell.btnComment.layer.cornerRadius = 5.0

        cell.btnReadMore.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnReadMore.layer.borderWidth = 1
        cell.btnReadMore.layer.cornerRadius = 5.0

        cell.dateMissingPersonPlace.text = self.MissingPeoplePlace[indexPath.row]
        cell.dateMissingPersonSince.text = self.MissingPeopleSince[indexPath.row]

        cell.btnGetUpdates.tag = indexPath.row
        cell.btnGetUpdates.addTarget(self, action: "GetUpdatesButton:", forControlEvents: .TouchUpInside)

        return cell

    }

in my cell.btnGetUpdates , I put an action as you can see in the last part of my CellForIndex code, GetUpdatesButton:

This is the code:

func GetUpdatesButton(sender: UIButton){
    println("Button Clicked \(sender.tag)")

    var sen: UIButton = sender
    var g : NSIndexPath = NSIndexPath(forRow: sen.tag, inSection: 0)
    var t : CustomCell = self.myTableView.cellForRowAtIndexPath(g) as! CustomCell
    t.btnGetUpdates.backgroundColor = UIColor.redColor()
    }

The problem is, NOT ONLY the button in index 0 is being highlighted, but I would also see random buttons from other index/rows being highlighted as I scroll my tableView down.

Where did I go wrong, how can I only update the button I clicked...and not other buttons..

I have 20 items ( 20 rows) and when I clicked button in row 0, rows 3, 6, 9....are also having highlighted buttons.

ROW 0 , button clicked

ROW 3, button clicked as well, though I did not really click it.

回答1:

This is occurring due to UITableview have reusablecell policy.In order to resolve this issue You need to maintain one array of selected items in cellForRowAtIndexPath method you have to verify weather this button is being hold by selected item array. if yes then apply selection styles otherwise apply normal style to it.

Check below source code for buttonclick:

func GetUpdatesButton(sender: UIButton) 
{
    var sen: UIButton = sender
    var g : NSIndexPath = NSIndexPath(forRow: sen.tag, inSection: 0)
    var t : CustomCell = self.myTableView.cellForRowAtIndexPath(g) as!   CustomCell
    t.btnGetUpdates.backgroundColor = UIColor.redColor()
   self.selectedButtonsArray.addObject(indexpath.row)
}

Below code for applying styles on buttons in CellForRowAtIndexPath:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell : CustomCell
    cell = tableView.dequeueReusableCellWithIdentifier("CustomCellID", forIndexPath: indexPath) as! CustomCell
    cell.strName.text = self.names[indexPath.row]
    cell.imgPerson.image = UIImage(named: "\(self.persons[indexPath.row])")!

    if(self.selectedButtonsArray.containsObject(indexpath.row)){

        cell.btnGetUpdates.backgroundColor = UIColor.redColor()
        cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnGetUpdates.layer.borderWidth = 1
        cell.btnGetUpdates.layer.cornerRadius = 5.0

    }else{

        cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnGetUpdates.layer.borderWidth = 1
        cell.btnGetUpdates.layer.cornerRadius = 5.0

   }

    cell.btnComment.layer.borderColor = UIColor.darkGrayColor().CGColor
    cell.btnComment.layer.borderWidth = 1
    cell.btnComment.layer.cornerRadius = 5.0

    cell.btnReadMore.layer.borderColor = UIColor.darkGrayColor().CGColor
    cell.btnReadMore.layer.borderWidth = 1
    cell.btnReadMore.layer.cornerRadius = 5.0

    cell.dateMissingPersonPlace.text = self.MissingPeoplePlace[indexPath.row]
    cell.dateMissingPersonSince.text = self.MissingPeopleSince[indexPath.row]

    cell.btnGetUpdates.tag = indexPath.row
    cell.btnGetUpdates.addTarget(self, action: "GetUpdatesButton:",forControlEvents: .TouchUpInside)

    return cell

}

I hope this helps to resolve your problem! Thanks.



回答2:

Inside the GetUpdatesButton() function , keep a flag value for the indexPath.row value in a separate array. Then reload the specific cell of the table view.

Now in the cellForRowAtIndexPath function make a condition of checking the flag value is set or not, If set then change background colour else set the default colour.

PS. there are different kinds of work arounds to solve the issue. Just understand the logic and go for the one which is useful in the code.



回答3:

This is because cells are being reused. So when you colour the cells using the button action, the cell's background is being painted which i guess is working fine but the situation is that when you scroll up or down, the previous cell which is having bg colour is being reused and hence you get the previous settings it was.

A tip would be to explicitly set the background colour of the UIButton and UITableViewCell in this method func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell, as everytime it will be reused the colour will be set as default and you will NOT get the previous colour it was being reused from.

Just set

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  cell.backgroundColor = [UIColor whiteColor];
  cell.btnGetUpdates setBackgroundColor:[UIColor whiteColor];
//with along the other code, add these two lines.
}

EDIT

for getting an effect like you want set an instance variable which stores the indexPath of the selected Cell something like an int.

In the button action method store the int to the button.tag property which is also the indexpath.row property of the cell.

in your cellForRowAtIndexPath method, do a check

if(indexpath.row == selectedIntIndexPath){
  //change the colour whatever you want.
}

Finally in the IBAction Method of the button call [self.tableView reloadData]

So the complete code will be something like this

@implementation ViewController{
int selectedIntIndexPath;
}

 -(IBAction)actionForButton:(id)sender{
UIButton *btn = (UIButton *)sender;
selectedIntIndexPath = btn.tag;
[self.customTableView reloadData];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UICustomTableViewCell *cell = (UICustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"reuseIdentifire" forIndexPath:indexPath];
if(indexPath.row == selectedIntIndexPath){
    // do your colour
  }
 return cell;
}


回答4:

Here my solutions, in order to expand @RaymondLedCarasco comment:

Tested in Swift 4 Xcode 9.3

Declare a propierty:

var numberCells: [Int] = []

When click the button of Cell:

self.numberCells.append(indexPath.row)

In CellForRowAtIndex check:

if self.numberCells.contains(indexPath.row) { ... } else { ... }


回答5:

Here most of TableViewCell problems I have solved, Like when clicking the cell button after scrolling the remaining rows may be changed and when selecting at didSelectRowAt indexPath: IndexPath the row, after scrolling the remaining rows may be selected. So I created an app to solve those problems. Here adding GitHub code Find the code

  • In the first screen, click on a red button and just scroll down you can't see other cells are affected automatically in UITableViewCell.

  • Clicking on didSelectRowAt indexPath: IndexPath in the first screen you can go to details screen that's the second screen, in that screen after selecting a row other rows won't be selected automatically in UITableViewCell.