【问题标题】:How to differentiate a button in a tableViewCell, being re-used in a tableView?如何区分 tableViewCell 中的按钮,在 tableView 中重复使用?
【发布时间】:2019-12-17 18:35:24
【问题描述】:

tableView 中有几个部分。每个部分都有 9 行。我在 TableViewCell 中设置了一个按钮,该按钮仅在每个部分的第 8 行和第 9 行可见。而且两者的功能不同,一个是“删除”按钮,一个是“设为默认”按钮。那么如何区分同一个按钮呢?

我在 TableViewCell 类中创建了一个函数让我们说buttonTapped()。我正在使用一个自定义按钮,我在其中声明了一个变量“indexPath”,以便区分按钮。当我配置单元格时,我将 indexPath.row 分配给按钮的 indexPath。因此,对于“删除”按钮,indexPath 变为 7(第 8 行),而对于“设为默认”,则为 8(第 9 行)。然后我必须在buttonTapped() 中切换按钮的 indexPath 以实现我的目标,情况为 7 和 8。有没有办法使此代码通用,即在情况下不硬编码 7 和 8。

@IBAction func buttonTapped(_ sender: CustomButton) {

        switch sender.indexPath {
        //Case 7 is 8th row in Table View
        case 7:
            //some code 
        //Case 8 is 9th row in Table View
        case 8:
            //some code
        default:
            break
        }

    }

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    您可以添加和枚举按钮所代表的可能操作。例如,在您的情况下,它将是:

    enum Actions {
    case none
    case delete
    case makeDefault
    }
    

    在您的 CustomButton 类中,您可以添加上面的枚举变量,而不是在您的案例 7 和 8 中的索引(行号)。然后您可以使用以下命令更新 buttonTapped 函数中的 switch 语句:

     @IBAction func buttonTapped(_ sender: CustomButton) {
           switch sender.action {
                case .delete:
                    //some code 
                case .makeDefault:
                    //some code
                case .none:
                    break
           }
      }
    

    现在在您的单元格配置功能中,您只需根据您的数据模型(或某些逻辑)设置操作类型。

    补充:

    我还建议在您的单元类和视图控制器之间使用委托,如 @Rohit Makwana 所述。

    protocol CustomDelegate {
        func cellView(didPerformAction action: Actions onIndexPath indexPath: IndexPath)
    }
    

    通过在你的视图控制器类中实现这个委托,你可以在这个方法中移动你的 buttonTapped 代码。

    【讨论】:

    • 谢谢@BilalAhmad。枚举确实使代码更具可读性和通用性。
    【解决方案2】:

    你可以通过使用标签来解决这个问题。由于 tag 是一个 Int 值,所以如果只有一个部分,您可以使用 button.tag = indexPath.row ,但由于有多个部分,您必须做一点点不同的标记。

    class CustomButton : UIButton {
        var tagIndexPath : IndexPath!
    
        // your rest of the code 
    }
    

    在单元类中,您设置单元的位置

    /*** you may follow any of the procedures
    // if you programitically create button
    private lazy var button : CustomButton {
        let button = CustomButton()
        // your init of button 
        return button
    }
    // if you take outlet 
    @IBOutlet weak var button : CustomButton!
    ***/
    
    func setup(indexPath : IndexPath) {
         // initially button is hidden 
         button.isHidden = true 
         button.tagIndexPath = indexPath
         if indexPath.row == 7 || indexPath.row == 8 {
             button.isHidden = false 
         }
         button.addTarget(self, #selector(buttonTapped), for: .touchUpInside)
    }
    
    @objc private func buttonTapped() {
        switch self.button.tagIndexPath {
           case 7:
              // your work
           case 8:
              // your work
           default:
             print("Nothing to do")
    
        }
    }
    
    

    【讨论】:

    • 在我看来,最干净、最原生的方式是使用委托。我在这里描述了一个非常相似的问题的解决方案stackoverflow.com/a/53760374/1278026
    • @OscarApeland 最干净和最原生的方式就像我的回答一样是一个闭包。
    • @AnkurLahiry 如果可以移动、插入或删除单元格,此解决方案将可靠地失败。
    • @vadian 命名一个使用闭包进行用户控制交互的 UIKit API(如果它也容易出现像您的答案这样的引用循环,则加分)
    • @OscarApeland UIKit 不是 native 因为它的 Objective-C 遗产。而且我的回答中的关闭不会导致保留周期。
    【解决方案3】:

    请试试这个方法。

    • 自定义委托 // 制作自定义委托

      protocol CustomDelegate {
          func buttonAction(WithIndexPath indexpath:IndexPath)
      }
      
    • TableView 单元格 // 你的自定义 TableView 单元格

      class CustomCell: UITableViewCell {
      
          @IBOutlet weak var yourButton: UIButton!
      
          var delegate : CustomDelegate?
          var indexPath: IndexPath?
      
          ... //Your code 
      
          @IBAction func customButtonAction(_ sender: UIButton) {
             self.delegate?.buttonAction(WithIndexPath: self.indexPath!)
          }
      }
      
    • 你的 ViewController

      class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomDelegate {
      
         @IBOutlet weak var tableView: UITableView!
      
         override func viewDidLoad() {
            super.viewDidLoad()
      
             // Please register cell If you need
             self.tableView.delegate   = self
             self.tableView.dataSource = self
         }
      
         //MARK:- TableView Delegate And DataSource
         func numberOfSections(in tableView: UITableView) -> Int {
             return 10 //As per your need
         }
      
         func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
             return 9 //As per your need
         }
      
         func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      
             let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
             cell.delegate = self //Must
             cell.indexPath = indexPath //Must
             cell.yourButton.setTitle("\(indexPath.section) : \(indexPath.row)", for: .normal)
             return cell
           }
      
          //MARK:- Delegate Method of CustomDelegate
          func buttonAction(WithIndexPath indexpath: IndexPath) {
      
             //Customize as per your need.
             switch indexpath.row {
             case 7:
                break
             case 8:
                break
             default:
             print("Nothing to do")
           }
        }
      }
      

    【讨论】:

    • 如果单元格可以移动、插入或删除,此解决方案也不起作用。
    • 你需要重新加载Tableview
    猜你喜欢
    • 2018-07-02
    • 2017-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多