Find the indexPath of a button inside a UITableViewCell on button click?
The code below returns the cell correctly:
func findSuperView(sender:UIButton!) -> UITableViewCell {
var superView : UIView? = sender.superview
var foundSuperView : UITableViewCell!
while superView != nil && foundSuperView == nil {
if let cell = superView as? UITableViewCell {
foundSuperView = cell
break
}
else {
superView = superView?.superview
}
}
return foundSuperView
}
But for looking up indexpath in tableview it fails:
var indexPath : NSIndexPath = self.table .indexPathForCell(findSuperView(sender))!
println("Section (indexPath)")
And I tried another way, but it failed:
var button : UIButton = sender as UIButton;
var touch: UITouch = events .allTouches()?.anyObject() as UITouch
var location : CGPoint = touch.locationInView(self.table)
var indexPath : NSIndexPath = self.table.indexPathForRowAtPoint(location)!
source to share
I don't know if there is an easy way to do this. ( Edit: Actually there is. Have a look at @ mustafa's second solution.) The workaround is to set the button tag indexPath.row
to cellForRowAtIndexPath
, then you can just access the button tag to find out which row it belongs to.
Warning: This workaround is fragile. It will not work correctly if you allow adding or removing rows from the table without calling tableView.reloadData()
. Have a look at @mustafa's solution which is much more robust.
source to share
Below is the candidate action method for your button TouchUpInside
.
func someAction(sender:UIButton, event: UIEvent) {
if let touch = event.touchesForView(sender)?.anyObject() as? UITouch {
let point = touch.locationInView(tableView)
if let indexPath = tableView.indexPathForRowAtPoint(point) {
// Do something with indexPath
}
}
}
And here's another one:
func someAction(sender: UIButton) {
let point = tableView.convertPoint(CGPointZero, fromView: sender)
if let indexPath = tableView.indexPathForRowAtPoint(point) {
// Do something with indexPath
}
}
source to share
You seem to be having trouble finding tableView
from your code that handles @IBAction
for your button.
You can create a subclass UIButton
that keeps track of both the button cell
and the button UITableView
that the cell belongs to. Then a simple call to tableView:indexPathForCell
in @IBAction
for a button.
MyButton.swift:
class MyButton: UIButton {
weak var myTable: UITableView?
weak var myCell: UITableViewCell?
}
CustomTableViewCell.swift:
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var myButton: MyButton!
@IBAction func whereAmI(button: MyButton) {
if let myCell = button.myCell, indexPath = button.myTable?.indexPathForCell(myCell) {
print("I am in row \(indexPath.row)")
}
}
}
In TableViewController.swift:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomTableViewCell
cell.myButton.myCell = cell
cell.myButton.myTable = tableView
// Other cell setup
return cell
}
To get this work done, it is important to set the classes for UIButton
both UITableViewCell
in MyButton
and CustomTableViewCell
in the Identity inspector. In addition, connect the button to the @IBOutlet
in CustomTableViewCell.swift
.
source to share
There was a problem with func findSuperView(sender:UIButton!) -> UITableViewCell
. Nothing guarantees that it foundSuperView
will matter.
func findSuperView(sender:UIButton!) -> UITableViewCell {
var superView : UIView? = sender.superview
var foundSuperView : UITableViewCell! // NOTE: The value is nil.
while superView != nil && foundSuperView == nil {
if let cell = superView as? UITableViewCell {
foundSuperView = cell
break
}
else {
superView = superView?.superview
}
}
return foundSuperView // NOTE: This will crash if foundSuperView == nil
}
A safer way to search for a view supercell returns an optional.
func findSuperCellOfView(view: UIView?) -> UITableViewCell? {
if view == nil {
return nil
} else if let cell = view as? UITableViewCell {
return cell
} else {
return findSuperCellOfView(view?.superview)
}
}
which will be used as follows.
if let cell = findSuperCellOfView(button) {
let indexPath = table.indexPathForCell(cell)
println("Section \(indexPath)")
}
source to share
If you are using a custom tableViewCell (which you probably are), you can simply create a variable.
class Cell: UITableViewCell {
var id = ""
@IBAction func buttonPressed(sender: AnyObject) {
print(id) // Can also call a function with 'id' as a parameter
}
}
and
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: Cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
cell.id = indexPath.row // Or however you wan't to give it an Id
return cell
}
source to share