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
Download Array of Images as Byte Array and Convert to Images
Ios Swift - Objective C Code Migration to Swift
Looking to Understand the iOS Uiviewcontroller Lifecycle
Check For Internet Connection With Swift
Figure Out Size of Uilabel Based on String in Swift
Nsfilemanager.Defaultmanager().Fileexistsatpath Returns False Instead of True
Objective-C and Swift Url Encoding
Programmatically Add Custom Event in the Iphone Calendar
Swift Language Nsclassfromstring
Controlling the Screenshot in the iOS 7 Multitasking Switcher
How to Center Horizontally Uicollectionview Cells
How to Change Button Title Alignment in Swift
Send and Receive Messages Through Nsnotificationcenter in Objective-C
How to Debug Memory Leaks When Leaks Instrument Does Not Show Them
How to Change the Name of an iOS App