Button Action in Custom Uitableviewcell Affects Other Cells

Button action in custom UITableViewCell affects other cells

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.

Accessing all the cells when a button in a cell is clicked

You can create a closure in custom UITableViewCell and call it whenever a button is pressed in the cell, i.e.

class TableViewCell: UITableViewCell {
@IBOutlet weak var button: UIButton!
var handler: (()->())?

@IBAction func buttonClicked(_ sender: UIButton) {
handler?()
}
}

Now, set the closure in tableView(_:cellForRowAt:) method and use visibleCells property to enable/disable the buttons in other cells, i.e.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.textLabel?.text = arr[indexPath.row]
cell.handler = {
if let visibleCells = tableView.visibleCells as? [TableViewCell] {
visibleCells.forEach({
$0.button.isEnabled = ($0 === cell)
})
}

}
return cell
}

In case you want to persist the enable/disable button states while reloading, you need to store in your model.

UITableViewCell Buttons with action

I was resolving this using a cell delegate method within UITableViewCell's subclass.

Quick overview:

1) Create a protocol

protocol YourCellDelegate : class {
func didPressButton(_ tag: Int)
}

2) Subclass your UITableViewCell (if you haven't done so):

class YourCell : UITableViewCell
{
var cellDelegate: YourCellDelegate?
@IBOutlet weak var btn: UIButton!
// connect the button from your cell with this method
@IBAction func buttonPressed(_ sender: UIButton) {
cellDelegate?.didPressButton(sender.tag)
}
...
}

3) Let your view controller conform to YourCellDelegate protocol that was implemented above.

class YourViewController: ..., YourCellDelegate {  ... }

4) Set a delegate, after the cell has been defined (for reusing).

let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! YourCell
cell.cellDelegate = self
cell.btn.tag = indexPath.row

5) In the same controller (where is your implemented UITableView delegate/datasource), put a method from YourCellDelegate protocol.

func didPressButton(_ tag: Int) {
print("I have pressed a button with a tag: \(tag)")
}

Now, your solution is not tag / number dependent. You can add as many buttons as you want, so you are ready to get response via delegate regardless how many buttons you want to install.

This protocol-delegate solution is preferred in iOS logic and it can be used for other elements in table cell, like UISwitch, UIStepper, and so on.

UIButton not responding used in a custom UITableViewCell

I would have userInteractionEnabled set to true on the table view cell as well. I would prevent taps using the UITableView allowsSelection to false

Also remember to remove the target and action in tableView:cellForRowAtIndexPath: since the cells are recycled, the button might already have the target and action, it might add a second.

UITableViewCell does not hold the state of custom button

The solution came from @Michael " any state you need must be maintained outside of the cell" since the tableView reuses the cells that are already created I had to add a property to the class Im populating the tableview with (I used a bool but it can be anything) and based on that property I set the state of the button in the method cellForRowAtIndexPath.

IBAction on a button in Custom UITableViewCell

You will set your UITableViewCell's class to your CustomCell's class and you will defined IBoutlets in CustomCell class and connect them.

And then you will set your Xib's file owner to your ViewController, and in your ViewController you will declare an

IBOutlet CustomCell *yourClassLevelCell;

and connect this IBOutlet to your Xib's UITableViewCell

now when you will initilize the cell inside your ViewController's method cellForRowAtIndexPath you will add target manually, something like this:

CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
cell = yourClassLevelCell;
[cell.button addTarget:self ... ];
//button is IBOutlet in your CustomCell class which you will have
//connected to your Button in xib
}

Custom UITableViewCell button action?

While I feel setting tag for the button is one way to go. You might need to write code to make sure each time the cell gets reused, the appropriate tag gets updated on the button object.

Instead I have a feeling this could work. Try this -

-(IBAction)myAction:(id)sender
{
CGPoint location = [sender locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
UITableViewCell *swipeCell = [self.tableView cellForRowAtIndexPath:indexPath];

NSLog(@"Selected row: %d", indexPath.row);
//......
}

Essentially what you are doing is getting the coordinates of where the click happened with respect to your tableView. After getting the coordinates, tableView can give you the indexPath by using the method indexPathForRowAtPoint:. You are good to go after this...

Voila, you have not just the indexPath but also the actual cell where the click happened. To get the actual data from your datasource (assuming its NSArray), you can do -

[datasource objectAtIndex:[indexPath row]];



Related Topics



Leave a reply



Submit