【问题标题】:Issue Detecting Button cellForRowAt问题检测按钮 cellForRowAt
【发布时间】:2018-03-04 20:20:34
【问题描述】:

我需要检测UITableViewController中的按钮是否被点击

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

 let LikesBtn = cell.viewWithTag(7) as! UIButton

}

【问题讨论】:

标签: ios swift uitableview


【解决方案1】:

第一步: 为您的自定义 UITableViewCell 创建子类,同时注册协议。

类似这样的:

protocol MyTableViewCellDelegate: class {
    func onButtonPressed(_ sender: UIButton, indexPath: IndexPath)
}

class MyTableViewCell: UITableViewCell {

    @IBOutlet var cellButton: UIButton!

    var cellIndexPath: IndexPath!
    weak var delegate: MyTableViewCellDelegate!


    override func awakeFromNib() {
        super.awakeFromNib()

        cellButton.addTarget(self, action: #selector(self.onButton(_:)), for: .touchUpInside)
    }

    func onButton(_ sender: UIButton) {
        delegate.onButtonPressed(sender, indexPath: cellIndexPath)
    }

}

在您的 TableViewController 中,确保它符合您刚刚创建的协议“MyTableViewCellDelegate”。

查看下面的代码以更好地理解。

class MyTableViewController: UITableViewController, MyTableViewCellDelegate {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as? MyTableViewCell {

            cell.cellIndexPath = indexPath
            cell.delegate = self

            return cell
        } else {
            print("Something wrong. Check your cell idetifier or cell subclass")
            return UITableViewCell()
        }
    }

    func onButtonPressed(_ sender: UIButton, indexPath: IndexPath) {
        print("DID PRESSED BUTTON WITH TAG = \(sender.tag) AT INDEX PATH = \(indexPath)")
    }
}

【讨论】:

  • 确保将delegate 设为weak 属性。我还建议不要将indexPath 存储在单元格中,因为一旦在表格中更早地插入或删除另一行,它就会失效。更小的一点,但我可能会建议将 MyTableViewCellDelegate 移动到扩展中,以使代码更有条理。
【解决方案2】:

Swift 中最简单、最有效的方法是回调闭包。

  • 子类UITableViewCellviewWithTag 标识 UI 元素的方法已过时。
  • 在Interface Builder中将自定义单元格的类设置为子类的名称,并将标识符设置为ButtonCellIdentifier

  • 添加callback 属性。

  • 添加一个动作并将按钮连接到该动作。

    class ButtonCell: UITableViewCell {
    
        var callback : (() -> Void)?
    
        @IBAction func buttonPressed(_ sender : UIButton) {
           callback?()
        }
    }
    
  • cellForRow 中将回调分配给自定义单元格。

    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
      }
    
  • 当按钮被按下时,回调被调用。索引路径被捕获。

编辑

如果可以添加或删除单元格,请注意。在这种情况下,将UITableViewCell 实例作为参数传递并从那里获取索引路径

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
  }

如果section 可以更改,那么协议/委托可能会更有效。

【讨论】:

    【解决方案3】:

    这是我使用的:

    首先在您的TableViewCell 上将按钮初始化为Outlet 及其action

    class MainViewCell: UITableViewCell {
    
    @IBOutlet weak var testButton: UIButton!
    
    @IBAction func testBClicked(_ sender: UIButton) {
    
        let tag = sender.tag //with this you can get which button was clicked 
    
    }
    
    
    
    }
    

    然后在 cellForRow 函数中的主控制器中,只需像这样初始化按钮的标签:

    class MainController: UIViewController, UITableViewDelegate, UITableViewDataSource, {
    
         func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MainViewCell
    
    
            cell.testButton.tag = indexPath.row        
    
            return cell
        }
    
    }
    

    【讨论】:

    • 不能再同意了,我也在我的项目中使用它并且像魅力一样工作
    • 如果表格视图支持删除、插入或移动行的能力,请不要使用索引路径作为标记。
    • @rmaddy 如果表格视图可以插入删除或移动行,那么它将重新加载自身,因此标签将再次初始化并且按钮将具有正确的索引,不是吗? (我没有检查过,但我相信它不会有问题)
    • 仅当您不必要地调用 reloadData 时,您不应该仅仅为了删除、插入或重新加载一行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    相关资源
    最近更新 更多