Detecting Which Uibutton Was Pressed in a Uitableview

Detecting which UIButton was pressed in a UITableView

In Apple's Accessory sample the following method is used:

[button addTarget:self action:@selector(checkButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

Then in touch handler touch coordinate retrieved and index path is calculated from that coordinate:

- (void)checkButtonTapped:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
if (indexPath != nil)
{
...
}
}

detecting uibutton pressed in tableview: Swift Best Practices

If your code allows, I'd recommend you set the UIButton tag equal to the indexPath.row, so when its action is triggered, you can pull the tag and thus row out of the button data during the triggered method. For example, in cellForRowAtIndexPath you can set the tag:

button.tag = indexPath.row
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

then in buttonClicked:, you can fetch the tag and thus the row:

func buttonClicked(sender:UIButton) {

let buttonRow = sender.tag
}

Otherwise, if that isn't conducive to your code for some reason, the Swift translation of this Objective-C answer you linked to:

- (void)checkButtonTapped:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
if (indexPath != nil)
{
...
}
}

is:

func checkButtonTapped(sender:AnyObject) {
let buttonPosition = sender.convert(CGPoint.zero, to: self.tableView)
let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
if indexPath != nil {
...
}
}

Tell to a button which row of the tableView we are tapping

In your cellForRow method assign tag to a button like shown below:

yourCell.yourButton.tag = indexPath.row

Then assign selector to it in cellForRow method.

yourCell.yourButton.addTarget(self, action: #selector(myClass.rowReload(_:)), forControlEvents: .TouchUpInside)

And in your rowReload method argument sender should have type UIButton and your method will be:

func rowReload(_ sender: UIButton) {

then you can access its tag and your IndexPath will be:

let index = IndexPath(row: sender.tag, section: 0)

Detect tap on a button in UITableViewCell for UITableView containing multiple sections

Objective-C

-(void)addItem:(UIButton*) sender
{

CGPoint touchPoint = [sender convertPoint:CGPointZero toView:mainTable]; // maintable --> replace your tableview name
NSIndexPath *clickedButtonIndexPath = [mainTable indexPathForRowAtPoint:touchPoint];

NSLog(@"index path.section ==%ld",(long)clickedButtonIndexPath.section);

NSLog(@"index path.row ==%ld",(long)clickedButtonIndexPath.row);


}

Swift3

 func addItem(sender: UIButton)
{
var touchPoint = sender.convert(CGPoint.zero, to: self.maintable)
// maintable --> replace your tableview name
var clickedButtonIndexPath = maintable.indexPathForRow(at: touchPoint)
NSLog("index path.section ==%ld", Int(clickedButtonIndexPath.section))
NSLog("index path.row ==%ld", Int(clickedButtonIndexPath.row))


}

Swift2 and above

func addItem(sender: UIButton)
{
var touchPoint: CGPoint = sender.convertPoint(CGPointZero, toView: mainTable)
// maintable --> replace your tableview name
var clickedButtonIndexPath: NSIndexPath = mainTable(forRowAtPoint: touchPoint)
NSLog("index path.section ==%ld", Int(clickedButtonIndexPath.section))
NSLog("index path.row ==%ld", Int(clickedButtonIndexPath.row))
}

Issue Detecting Button cellForRowAt

The easiest and most efficient way in Swift is a callback closure.

  • Subclass UITableViewCell, the viewWithTag way to identify UI elements is outdated.
  • Set the class of the custom cell to the name of the subclass and set the identifier to ButtonCellIdentifier in Interface Builder.

  • Add a callback property.

  • Add an action and connect the button to the action.

    class ButtonCell: UITableViewCell {

    var callback : (() -> Void)?

    @IBAction func buttonPressed(_ sender : UIButton) {
    callback?()
    }
    }
  • In cellForRow assign the callback to the custom cell.

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCellIdentifier", for: indexPath) as! ButtonCell
    cell.callback = {
    print("Button pressed", indexPath)
    }
    return cell
    }
  • When the button is pressed the callback is called. The index path is captured.

Edit

There is a caveat if cells can be added or removed. In this case pass the UITableViewCell instance as parameter and get the index path from there

class ButtonCell: UITableViewCell {

var callback : ((UITableViewCell) -> Void)?

@IBAction func buttonPressed(_ sender : UIButton) {
callback?(self)
}
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCellIdentifier", for: indexPath) as! ButtonCell
let item = dataSourceArray[indexPath.row]
// do something with item
cell.callback = { cell in
let actualIndexPath = tableView.indexPath(for: cell)!
print("Button pressed", actualIndexPath)
}
return cell
}

If even the section can change, well, then protocol/delegate may be more efficient.



Related Topics



Leave a reply



Submit