【问题标题】:get indexPath of UITableViewCell on click of Button from Cell单击单元格中的按钮获取 UITableViewCell 的 indexPath
【发布时间】:2017-01-27 21:06:02
【问题描述】:

我在UITableViewCell 中有一个按钮(红色十字),单击该按钮我想获得UITableViewCellindexPath

现在我像这样为每个按钮分配标签 cell.closeButton.tag = indexPath.section 并且单击按钮我得到indexPath.section 值,如下所示:

@IBAction func closeImageButtonPressed(sender: AnyObject) {
  data.removeAtIndex(sender.tag)
  tableView.reloadData()
}

这是正确的实施方式还是有其他干净的方式来做到这一点?

【问题讨论】:

  • 顺便问一下,为什么你删除一个部分后要重新加载整个表?只需致电tableView.deleteSections(NSIndexSet(index: sender.tag), withRowAnimation: .None)
  • 是的,我可以做到。
  • 或许你可以看看下面的帖子:stackoverflow.com/a/41629633/387507
  • 您能解决问题吗?
  • @Mr.Bista 是的,我做到了。

标签: ios uitableview uibutton swift2


【解决方案1】:

使用委托:

MyCell.swift:

import UIKit

//1. delegate method
protocol MyCellDelegate: AnyObject {
    func btnCloseTapped(cell: MyCell)
}

class MyCell: UICollectionViewCell {
    @IBOutlet var btnClose: UIButton!

    //2. create delegate variable
    weak var delegate: MyCellDelegate?

    //3. assign this action to close button
    @IBAction func btnCloseTapped(sender: AnyObject) {
        //4. call delegate method
        //check delegate is not nil with `?`
        delegate?.btnCloseTapped(cell: self)
    }
}

MyViewController.swift:

//5. Conform to delegate method
class MyViewController: UIViewController, MyCellDelegate, UITableViewDataSource,UITableViewDelegate {

    //6. Implement Delegate Method
    func btnCloseTapped(cell: MyCell) {
        //Get the indexpath of cell where button was tapped
        let indexPath = self.collectionView.indexPathForCell(cell)
        print(indexPath!.row)
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as! MyCell
        //7. delegate view controller instance to the cell
        cell.delegate = self

        return cell
    }
}

【讨论】:

    【解决方案2】:

    如何在 Swift 4 中使用按钮选择器获取用于点击按钮的单元格 indexPath

    @objc func buttonClicked(_sender:UIButton){
    
     let buttonPosition = sender.convert(CGPoint.zero, to: self.tableView)
     let indexPath = self.tableView.indexPathForRow(at:buttonPosition)
     let cell = self.tableView.cellForRow(at: indexPath) as! UITableViewCell
     print(cell.itemLabel.text)//print or get item
    }
    

    【讨论】:

      【解决方案3】:

      尝试充分利用快速闭包:简单、快速、轻松。

      在 cellForRowAtIndexPath 方法中:

      let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCellIdentifier", for: indexPath) as! CustomCell
      
      cell.btnTick.mk_addTapHandler { (btn) in
           print("You can use here also directly : \(indexPath.row)")
           self.btnTapped(btn: btn, indexPath: indexPath)
      }
      

      cellForRowAtIndexPath 方法外供外部使用的Selector 方法:

      func btnTapped(btn:UIButton, indexPath:IndexPath) {
          print("IndexPath : \(indexPath.row)")
      }
      

      UIButton 的扩展:

      extension UIButton {
      
          private class Action {
              var action: (UIButton) -> Void
      
              init(action: @escaping (UIButton) -> Void) {
                  self.action = action
              }
          }
      
          private struct AssociatedKeys {
              static var ActionTapped = "actionTapped"
          }
      
          private var tapAction: Action? {
              set { objc_setAssociatedObject(self, &AssociatedKeys.ActionTapped, newValue, .OBJC_ASSOCIATION_RETAIN) }
              get { return objc_getAssociatedObject(self, &AssociatedKeys.ActionTapped) as? Action }
          }
      
      
          @objc dynamic private func handleAction(_ recognizer: UIButton) {
              tapAction?.action(recognizer)
          }
      
      
          func mk_addTapHandler(action: @escaping (UIButton) -> Void) {
              self.addTarget(self, action: #selector(handleAction(_:)), for: .touchUpInside)
              tapAction = Action(action: action)
      
          }
      }
      

      【讨论】:

        【解决方案4】:

        在 Swift 4 中,只需使用这个:

        func buttonTapped(_ sender: UIButton) {
        
            let buttonPostion = sender.convert(sender.bounds.origin, to: tableView)
        
            if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
                let rowIndex =  indexPath.row
            }
        }
        

        【讨论】:

          【解决方案5】:

          您也可以通过这种方式从CGPoint 获取NSIndexPath

          @IBAction func closeImageButtonPressed(sender: AnyObject) {
              var buttonPosition = sender.convertPoint(CGPointZero, to: self.tableView)
              var indexPath = self.tableView.indexPathForRow(atPoint: buttonPosition)!
          }
          

          【讨论】:

          • CGPointZero 是位置为 (0,0) 的点常数。零点相当于CGPointMake(0,0)。它会将您的 buttonPosition 转换为 indexpath。
          【解决方案6】:

          创建一个自定义的 UIButton 类并声明一个这样的存储属性,并使用它从 callFroRowAtIndexPath 检索分配的 indexPath。

          class VUIButton: UIButton {
              var indexPath: NSIndexPath = NSIndexPath()
          }
          

          这是您的 indexPath 在任何情况下都不会出错的完整证明解决方案。尝试一次。

          【讨论】:

            【解决方案7】:
            //
            //  ViewController.swift
            //  Table
            //
            //  Created by Ngugi Nduung'u on 24/08/2017.
            //  Copyright © 2017 Ngugi Ndung'u. All rights reserved.
            //
            
            import UIKit
            
            class ViewController: UITableViewController{
            
                let identifier = "cellId"
                var items = ["item1", "2", "3"]
                override func viewDidLoad() {
                    super.viewDidLoad()
                    // Do any additional setup after loading the view, typically from a nib.
                    self.title = "Table"
                    tableView.register(MyClass.self, forCellReuseIdentifier: "cellId")
                }
            
                //Return number of cells you need
                override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
                    return items.count
                }
            
                override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! MyClass
                    cell.controller = self
                    cell.label.text  = items[indexPath.row]
                    return cell
            
                }
            
                // Delete a cell when delete button on cell is clicked 
                func delete(cell: UITableViewCell){
                    print("delete")
                    if let deletePath = tableView.indexPath(for: cell){
                        items.remove(at: deletePath.row)
                        tableView.deleteRows(at: [deletePath], with: .automatic)
                    }
            
                }
            
            }
            
            class MyClass : UITableViewCell{
                var controller : ViewController?
                override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
                        super.init(style: style, reuseIdentifier: reuseIdentifier)
                        setUpViews()
                }
            
                required init?(coder aDecoder: NSCoder) {
                    super.init(coder: aDecoder)
                    fatalError("init(coder:) has not been implemented")
                }
            
                let label : UILabel = {
                    let label = UILabel()
                    label.text = "My very first cell"
                    label.translatesAutoresizingMaskIntoConstraints = false
                    return label
                }()
            
                let btn : UIButton = {
                   let bt = UIButton(type: .system)
                    bt.translatesAutoresizingMaskIntoConstraints = false
                    bt.setTitle("Delete", for: .normal)
            
            
                    bt.setTitleColor(.red, for: .normal)
                    return bt
                }()
            
                func handleDelete(){
                   controller?.delete(cell: self)
                }
                func setUpViews(){
                    addSubview(label)
                    addSubview(btn)
                    btn.addTarget(self, action: #selector(MyClass.handleDelete), for: .touchUpInside)
                    btn.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
                    label.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 16).isActive = true
                    label.widthAnchor.constraint(equalTo: self.widthAnchor , multiplier: 0.8).isActive = true
                    label.rightAnchor.constraint(equalTo: btn.leftAnchor).isActive = true
            
                }
            }
            

            这是一个完整的示例,可以回答您的问题。

            【讨论】:

              【解决方案8】:

              在你的 cellForRow 中:

              #import <objc/runtime.h>
              
              func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
                  setAssociatedObject(object: YOURBUTTON, key: KEYSTRING, value: indexPath)
              }
              
              @IBAction func closeImageButtonPressed(sender: AnyObject) {
                  let val = getAssociatedObject(object: sender, key: KEYSTROKING)
              }
              

              这里 val 是您的 indexPath 对象,您可以传递任何对象,就像您可以分配传递单元格对象并在按钮操作中获取它一样。

              【讨论】:

                【解决方案9】:

                试试这个:

                override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                    var cell = (tableView.dequeueReusableCell(withIdentifier: "MainViewCell", forIndexPath: indexPath) as! MainTableViewCell)
                    cell.myButton().addTarget(self, action: Selector("myClickEvent:event:"), forControlEvents: .touchUpInside)
                    return cell
                }
                

                此函数获取行点击的位置

                @IBAction func myClickEvent(_ sender: Any, event: Any) {
                    var touches = event.allTouches()!
                    var touch = touches.first!
                    var currentTouchPosition = touch.location(inView: feedsList)
                    var indexPath = feedsList.indexPathForRow(atPoint: currentTouchPosition)!
                    print("position:\(indexPath.row)")
                }
                

                【讨论】:

                  【解决方案10】:
                  class MyCell: UICollectionViewCell {
                  
                     @IBOutlet weak var btnPlus: UIButton!
                  
                  }
                  
                  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 
                   UITableViewCell {
                  
                  
                  cell.btnPlus.addTarget(self, action: #selector(increment_Action(sender:)), 
                   for: .touchUpInside)
                  cell.btnPlus.tag = indexPath.row
                  cell.btnPlus.superview?.tag = indexPath.section
                  }
                  
                  @objc func increment_Action(sender: UIButton) {
                          
                  let btn = sender as! UIButton
                  let section = btn.superview?.tag ?? 0
                  
                  let row = sender.tag
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2017-03-07
                    • 2014-01-06
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-04-24
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多