indexPathForSelectedRow

indexPathForSelectedRow

本文介绍了单击表格视图单元格上的按钮时如何获取 indexPath.row?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,上图是我的待办事项列表应用程序的 UI,现在我只想在单击 tableviewcell 中的详细信息按钮时显示项目的详细信息(第一项、第二项等).因此,为了获取项目的属性,我需要知道我刚刚单击详细信息按钮的行的 indexPath.

Hello the image above is the UI of my todo list app, now I just want to show the detail of item (First Item, second Item etc) when I click the detail button in the tableviewcell. So in order to get the property of the item, I need to know the indexPath of the row that I just clicked on the detail button.

我已经尝试了 tableview 的一些属性,例如 didSelectRowAtindexPathForSelectedRow,但都不起作用.对于 didSelectRowAt 用户需要先单击该行然后单击详细信息按钮,这不是我想要的,并且 indexPathForSelectedRow 对我不起作用.

I have tried some properties of the tableview like didSelectRowAt, or indexPathForSelectedRow, but both not work. For didSelectRowAt user need to click on the row first then click the detail button, and that's not what I want, and the indexPathForSelectedRow is not working for me.

推荐答案

对于此类问题,一个常见的通用解决方案是将按钮的 @IBAction 连接到单元格中的处理程序 (不在视图控制器中),然后使用委托协议模式,以便单元格可以在点击按钮时告诉表格.关键是当单元格执行此操作时,它将提供对自身的引用,然后视图控制器可以使用它来确定适当的 indexPath(以及行).

A common, generalized solution for this type of problem is to connect the @IBAction of the button to a handler in the cell (not in the view controller), and then use a delegate-protocol pattern so the cell can tell the table when the button was tapped. The key is that when the cell does this, it will supply a reference to itself, which the view controller can then use to determine the appropriate indexPath (and thus the row).

例如:

  • 给你的 UITableViewCell 子类一个协议:

protocol CustomCellDelegate: class {
    func cell(_ cell: CustomCell, didTap button: UIButton)
}

  • @IBAction 连接到单元格(不是视图控制器)并调用委托方法:

  • Hook up the @IBAction to the cell (not the view controller) and have that call the delegate method:

    class CustomCell: UITableViewCell {
        weak var delegate: CustomCellDelegate?
    
        @IBOutlet weak var customLabel: UILabel!
    
        func configure(text: String, delegate: CustomCellDelegate) {
            customLabel.text = text
            self.delegate = delegate
        }
    
        @IBAction func didTapButton(_ button: UIButton) {
            delegate?.cell(self, didTap: button)
        }
    }
    

  • 显然,在创建单元格时,调用 configure 方法,并传递对自身的引用作为委托:

  • Obviously, when the cell is created, call the configure method, passing, amongst other things, a reference to itself as the delegate:

    extension ViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
            let text = ...
            cell.configure(text: text, delegate: self)
            return cell
        }
    }
    

  • 最后,让委托方法调用 indexPath(for:) 来确定相关单元格的索引路径:

  • Finally, have the delegate method call indexPath(for:) to determine the index path for the cell in question:

    extension ViewController: CustomCellDelegate {
        func cell(_ cell: CustomCell, didTap button: UIButton) {
            guard let indexPath = tableView.indexPath(for: cell) else { return }
    
            // use `indexPath.row` here
        }
    }
    

  • 另一种方法是使用闭包,但再次使用相同的通用模式将按钮 @IBAction 挂接到单元格,但让它调用闭包而不是委托方法:

    The other approach is to use closures, but again using the same general pattern of hooking the button @IBAction to the cell, but have it call a closure instead of the delegate method:

    • 定义带有闭包的自定义单元格,当点击按钮时将调用该闭包:

    • Define custom cell with closure that will be called when the button is tapped:

    class CustomCell: UITableViewCell {
        typealias ButtonHandler = (CustomCell) -> Void
    
        var buttonHandler: ButtonHandler?
    
        @IBOutlet weak var customLabel: UILabel!
    
        func configure(text: String, buttonHandler: @escaping ButtonHandler) {
            customLabel.text = text
            self.buttonHandler = buttonHandler
        }
    
        @IBAction func didTapButton(_ button: UIButton) {
            buttonHandler?(self)
        }
    }
    

  • 当表视图数据源创建单元格时,提供一个处理程序闭包:

  • When the table view data source creates the cell, supply a handler closure:

    extension ViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
            let text = ...
            cell.configure(text: text, buttonHandler: { [weak self] cell in  // the `[weak self]` is only needed if this closure references `self` somewhere
                guard let indexPath = tableView.indexPath(for: cell) else { return }
    
                // use `indexPath` here
            })
            return cell
        }
    }
    

  • 我个人更喜欢委托协议模式,因为它往往能更好地扩展,但两种方法都有效.

    I personally prefer the delegate-protocol pattern, as it tends to scale more nicely, but both approaches work.

    请注意,在这两个示例中,我都刻意避免将 indexPath 保存在单元格中,本身(或更糟的是,标签"值).通过这样做,如果稍后从表中插入和删除行,它可以保护您不会错位.

    Note, in both examples, I studiously avoided saving the indexPath in the cell, itself (or worse, "tag" values). By doing this, it protects you from getting misaligned if rows are later inserted and deleted from the table.

    顺便说一下,我使用了相当通用的方法/闭包名称.在真实的应用程序中,您可能会为它们指定更有意义的名称,例如,didTapInfoButtondidTapSaveButton 等)以阐明功能意图.

    By the way, I used fairly generic method/closure names. In a real app, you might give them more meaningful names, e.g., didTapInfoButton, didTapSaveButton, etc.) that clarifies the functional intent.

    这篇关于单击表格视图单元格上的按钮时如何获取 indexPath.row?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    08-14 11:52