当按下按钮时,如何找到UITableViewCell中按钮的indexPath?

3
下面的代码正确地返回单元格:
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 
}

但是在表视图中查找indexpath时会崩溃:

var indexPath : NSIndexPath = self.table .indexPathForCell(findSuperView(sender))!
println("Section (indexPath)")

我尝试了另一种方法,但没有成功:

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)!
6个回答

10

这里是一个候选的操作方法,用于您的按钮的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
        }
    }
}

这里还有另一个:

func someAction(sender: UIButton) {
    let point = tableView.convertPoint(CGPointZero, fromView: sender)
    if let indexPath = tableView.indexPathForRowAtPoint(point) {
        // Do something with indexPath
    }
}

感谢您的快速回复,但是“tableView.indexPathForRowAtPoint(point)”和“tableView.indexPathForRowAtPoint(point)”在我的情况下仍然返回nil。在我的情况下,“table”通过IBOutlet连接,而按钮是部分(TableViewCell)的子视图。 - Arsalan Ansari

1
你似乎在代码中找不到处理按钮的@IBAction时的tableView。
你可以创建一个UIButton子类,跟踪包含按钮的cell和包含该cell的UITableView。然后在按钮的@IBAction中简单地调用tableView:indexPathForCell。

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)")
        }
    }
}

在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
}

为了使其正常工作,重要的是在“Identity Inspector”中将UIButtonUITableViewCell的类设置为MyButtonCustomTableViewCell。另外,将按钮与CustomTableViewCell.swift中的@IBOutlet相连接。

0

func findSuperView(sender:UIButton!) -> UITableViewCell 存在问题。没有任何保证 foundSuperView 会有一个值。

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
}

找到视图的超级单元格的更安全的方法是返回一个可选项。
func findSuperCellOfView(view: UIView?) -> UITableViewCell? {
    if view == nil {
        return nil
    } else if let cell = view as? UITableViewCell {
        return cell
    } else {
        return findSuperCellOfView(view?.superview)
    }
}

它将被用于以下情况。

if let cell = findSuperCellOfView(button) {
    let indexPath = table.indexPathForCell(cell)
    println("Section \(indexPath)")
}

非常感谢您的回复,但是 "table.indexPathForCell(cell)" 在我的情况下仍然返回 nil。在我的情况下,'table' 是通过IBOutlet连接的,而按钮是单元格中某个区域的子视图。 - Arsalan Ansari

0
如果您正在使用自定义的tableViewCell(这很可能是),那么您可以创建一个变量。
class Cell: UITableViewCell {

    var id = ""

    @IBAction func buttonPressed(sender: AnyObject) {
        print(id) // Can also call a function with 'id' as a parameter
    }
}

而且:

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
}

0

这段代码在Swift 5中运行良好:

private func onTapButtonInsideCell(button: UIButton, event: UIEvent) {

    guard let touches = event.touches(for: button), !touches.isEmpty else {
        return
    }

    let touch = touches[touches.startIndex]
    let point = touch.location(in: tableView)

    guard let indexPath = tableView.indexPathForItem(at: point) else {
        return
    }

    print("onTapButtonInsideCell() indexPath.row=\(indexPath.row)")
}

Github代码片段:https://gist.github.com/rsaenzi/13dc00b5cb5a09efa84eaff3ff4682af

-1

我不知道是否有一种简单的方法来做到这一点。(编辑:实际上是有的。请看@mustafa的第二个解决方案。)一个解决方法是在cellForRowAtIndexPath中将按钮的标签设置为indexPath.row,然后您可以访问按钮的标签以找出它属于哪一行。

警告:这个解决方法很脆弱。如果您允许从表格中添加或删除行而没有调用tableView.reloadData(),它将无法正确工作。请查看@mustafa的解决方案,它更加健壮。


谢谢您的快速回复,我已经尝试了您的解决方案,它对我很有效。但是我希望有一个更好的替代方案来解决这个问题。 - Arsalan Ansari
不,如果可以添加或删除任何行,则使用基于indexPath的标记无法正常工作。 - rmaddy
@rmaddy。好主意。我更新了我的答案来注意这一点。由于其他答案对OP无效,我采取了一种全新的方法来回答问题。由于我的原始答案被OP接受,我不想编辑它并给人留下我的新答案已被接受的印象。 - vacawama

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接