Как получить indexPath.row, когда я нажимаю кнопку в ячейке табличного представления? - PullRequest
1 голос
/ 03 мая 2019

This is my app

Здравствуйте, изображение выше - это интерфейс моего приложения списка задач, теперь я просто хочу показать детали элемента (первый элемент, второй элемент и т. Д.), КогдаЯ нажимаю кнопку детализации в ячейке таблицы.Таким образом, чтобы получить свойство элемента, мне нужно знать indexPath строки, которую я только что нажал на кнопку детализации.

Я пробовал некоторые свойства табличного представления, такие как didSelectRowAt или indexPathForSelectedRow, но оба не работают.Для didSelectRowAt пользователь должен сначала нажать на строку, а затем нажать кнопку детализации, и это не то, что я хочу, и indexPathForSelectedRow не работает для меня.

Ответы [ 2 ]

2 голосов
/ 03 мая 2019

Общее, обобщенное решение для этого типа проблемы состоит в том, чтобы подключить @IBAction кнопки к обработчику в ячейке (не в контроллере представления), а затем использовать шаблон протокола делегата, чтобы ячейка могла сказатьтаблица, когда кнопка была нажата.Ключ заключается в том, что когда ячейка делает это, она предоставляет ссылку на себя, которую контроллер представления затем может использовать для определения соответствующего indexPath (и, следовательно, строки).

Например:

  • Дайте вашему подклассу UITableViewCell протокол:

    protocol CustomCellDelegate: class {
        func cell(_ cell: CustomCell, didTap button: UIButton)
    }
    
  • Подключите @IBAction к ячейке (не к контроллеру представления) и получитевызовите метод делегата:

    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, передав, среди прочего, ссылку на себя в качестве делегата:

    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:), чтобы определить путь индекса для рассматриваемой ячейки:

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

Другой подход заключается в использовании замыканий, но опять-таки с использованием того же общего шаблона для привязки кнопки @IBAction к ячейке, но для вызова функции замыкания вместо метода делегата:

  • Определить пользовательскую ячейку с закрытием, которая будет вызываться, когда кнопка is постучал:

    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)
        }
    }
    
  • Когда источник данных табличного представления создает ячейку, укажите закрытие обработчика:

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

Я личнопредпочитаю шаблон протокола делегата, так как он имеет тенденцию лучше масштабироваться, но оба подхода работают.


Обратите внимание, что в обоих примерах я старательно избегал сохранения indexPath в самой ячейке (илихуже, «пометить» значения).Делая это, он защищает вас от смещения, если строки позже вставляются и удаляются из таблицы.


Кстати, я использовал довольно общие имена методов / замыканий.В реальном приложении вы можете дать им более значимые имена, например, didTapInfoButton, didTapSaveButton и т. Д.), Которые проясняют функциональные цели.

1 голос
/ 03 мая 2019

Реализация метода делегата tableView (_: accessoryButtonTappedForRowWith:)

func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath)

Однако, если вы хотите перейти к другому контроллеру, подключите переход к кнопке представления аксессуара

Если кнопка является пользовательской кнопкой, см. Мой ответ в Кнопка обнаружения проблем cellForRowAt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...