【问题标题】:UITableViewCell Buttons with action带有动作的 UITableViewCell 按钮
【发布时间】:2017-02-18 05:08:15
【问题描述】:

您好,我有一个自定义 UITableViewCell,其中包含三个按钮来处理购物车功能,加号、减号和删除按钮,我需要知道哪个单元格已被触摸。

我已经尝试使用“标签解决方案”,但由于单元格的生命周期,它无法正常工作。

谁能帮我找到解决办法?

提前致谢

【问题讨论】:

  • 请提供一些代码,说明您是如何使用标签的。如果每次重用单元格时都将它们设置在 cellForRowAtIndexPath 中,那么生命周期应该没有任何问题。

标签: ios swift uitableview uibutton swift3


【解决方案1】:

我在 UITableViewCell 的子类中使用单元格委托方法解决了这个问题。

快速概览:

1) 创建协议

protocol YourCellDelegate : class {
    func didPressButton(_ tag: Int)
}

2) 子类你的UITableViewCell(如果你还没有这样做的话):

class YourCell : UITableViewCell
{
     var cellDelegate: YourCellDelegate?   
      @IBOutlet weak var btn: UIButton!
    // connect the button from your cell with this method
    @IBAction func buttonPressed(_ sender: UIButton) {
        cellDelegate?.didPressButton(sender.tag)
    }         
    ...
}

3) 你的视图控制器符合上面实现的YourCellDelegate协议。

class YourViewController: ..., YourCellDelegate {  ... }

4) 设置委托,在定义单元格之后(以供重用)。

let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! YourCell
cell.cellDelegate = self
cell.btn.tag = indexPath.row

5) 在同一个控制器中(您实现的 UITableView 委托/数据源在哪里),放置来自YourCellDelegate 协议的方法

func didPressButton(_ tag: Int) {
     print("I have pressed a button with a tag: \(tag)")
}

现在,您的解决方案不依赖于标签/数字。您可以根据需要添加任意数量的按钮,因此无论要安装多少按钮,您都可以通过委托获得响应。

iOS 逻辑中首选此协议委托解决方案,它可用于表格单元格中的其他元素,如UISwitchUIStepper 等。

【讨论】:

  • 这个解决方案看起来很神奇,但我还是需要知道我按下了哪个单元格,使用tag参数时问题还是一样
  • 您可能只需要在来自单元格的按钮和在步骤 2 中键入的 IBAction buttonPressed() 方法之间添加一个连接)
  • cell.tag = indexPath.row 只给我所有行的 0。第 2 步中的 sender.tag 不应该是 self.tag,因为它是您在第 4 步中设置为 indexPath.row 的单元格标签。在第 2 步中使用 self.tag 而不是 sender.tag 对我来说可以正常工作。
  • 如果tableview也实现了section,你如何解析单元格索引路径的section部分?
  • 要处理多个部分,请给您的单元格一个 indexPath 变量并设置它而不是使用标记。
【解决方案2】:

您还可以使用 tableViewCell 视图的层次结构获取选定的按钮索引。

使用以下步骤:

  1. 将选择器添加到 tableview 的 cellForRowAtIndexpath :

    btn?.addTarget(self, action:#selector(buttonPressed(_:)), for:.touchUpInside)
    

2 。使用以下方法获取 indexPath:

func buttonPressed(_ sender: AnyObject) {
        let button = sender as? UIButton
        let cell = button?.superview?.superview as? UITableViewCell
        let indexPath = tblview.indexPath(for: cell!)
        print(indexPath?.row)
    }

【讨论】:

  • 这是一个很好的解决方案,但强烈支持视图的设计方式。如果按钮位于另一个子视图中(例如堆栈视图),您可能会得到一长串超级视图调用来检测按钮所在的单元格。
【解决方案3】:

按照社区的广泛建议,将 IBOutlets 设为私有后,我遇到了同样的问题。

这是我的解决方案:

protocol YourCellDelegate: class {
    func didTapButton(_ sender: UIButton)
}

class YourCell: UITableViewCell {

    weak var delegate: YourCellDelegate?

    @IBAction func buttonTapped(_ sender: UIButton) {
        delegate?.didTapButton(sender)
    }
}

class ViewController: UIViewController, YourCellDelegate {

    func didTapButton(_ sender: UIButton) {
        if let indexPath = getCurrentCellIndexPath(sender) {
            item = items[indexPath.row]
        }
    }

    func getCurrentCellIndexPath(_ sender: UIButton) -> IndexPath? {
        let buttonPosition = sender.convert(CGPoint.zero, to: tableView)
        if let indexPath: IndexPath = tableView.indexPathForRow(at: buttonPosition) {
            return indexPath
        }
        return nil
    }
}

【讨论】:

  • 您的解决方案应该被接受。在将单元格的按钮配置为绑定到视图控制器的操作时,它也可以在不使用 UITableViewCell 子类的委托模式的情况下工作。
  • 不用 .tag 属性好多了,而且干净多了!
  • 另一种代替转换点的方法是使用superview获取单元格,然后调用indexPath(for: UITableViewCell)
  • 您在 cellforrowatindexpath 中忘记了 cell.delegate = self。
  • 谢谢@DeyaEldeen - 这是唯一需要的其他东西。
【解决方案4】:

SWIFT 4.*

也可以像下面这样,不需要太多的编码和委托,简单易行。

将以下代码放入cellForItemAt 中以获取UICollectionViewcellForRowAt 以获取UITableView

cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: #selector(buttonSelected), for: .touchUpInside)

你的方法将是

@objc func buttonSelected(sender: UIButton){
    print(sender.tag)
}

就是这样。

【讨论】:

    【解决方案5】:

    @pedrouan 很棒,除了使用按钮的 tag 选项。在许多情况下,当您在tableViewCell 上设置按钮时,这些按钮将修改 tableView 数据源。(例如 InsertRow、DeleteRow)。

    但即使新单元格是inserteddeleted,按钮的标签也不会更新。因此,最好将cell本身作为参数传递,而不是将按钮的tag传递给参数。

    这是我实现这一目标的示例。

    你的ExampleCell

    protocol ExampleCellDelegate: class {
        func didTapButton(cell: ExampleCell)
    }
    
    class ExampleCell: UITableViewCell {
    
        weak var cellDelegate: ExampleCellDelegate?
    
        @IBAction func btnTapped(_ sender: UIButton) {
            cellDelegate?.didTapButton(cell: self)
        }
    }
    

    你的ViewController

    class ViewController: ExampleCellDelegate {
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            if let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) as? ExampleCell {
    
                cell.cellDelegate = self
                return cell
            }
            return UITableViewCell()
        }
    
        func didTapButton(cell: ExampleCell) {
            if let indexPath = tableView.indexPath(for: cell) {
                // do Something
            }
        }
    }
    

    【讨论】:

    • 这是包含最佳实践的唯一正确答案,这很有趣,因为它的赞成票为零。只需查看 UITableViewDelegate 之类的示例即可获得指导。您应该在委托方法中传递单元格本身。然后,例如,在您的控制器中,您可以获取单元格的索引路径,然后可用于通过 indexPath.row 访问数据源中的正确数据。依赖原始的标签是没有意义的,而且必然会崩溃。
    • 这很好!不错:))
    【解决方案6】:

    Tableview 单元格中的 UIButton。在 swift 4.2 中以编程方式创建动作方法

    cell.btnlike.addTarget(self, action: #selector(buttonbtnlikePressed(_:event:)), for: .touchUpInside)
    
    
    @objc func buttonbtnlikePressed(_ sender: Any, event: Any) {
            let point : CGPoint = (sender as AnyObject).convert(CGPoint.zero, to:tblPost)
            var indexPath =  self.tblPost!.indexPathForRow(at: point)
            if let btnlike = sender as? UIButton{
                if btnlike.isSelected{
                    btnlike.isSelected = false
                }else{
                    btnlike.isSelected = true
                }
            }
        }
    

    【讨论】:

      【解决方案7】:

      swift 4.2

      你也可以使用闭包代替委托

      1) 在你的 UITableViewCell 中:

       class ExampleCell: UITableViewCell {
          //create your closure here  
               var buttonPressed : (() -> ()) = {}
      
              @IBAction func buttonAction(_ sender: UIButton) {
          //Call your closure here 
                  buttonPressed()
              }
          }
      

      2) 在你的 ViewController 中

      class ViewController:  UIViewController,  UITableViewDataSource, UITableViewDelegate {
       func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) as! ExampleCell
         cell.buttonPressed = {
                //Code
                 }
      return cell 
        }
      }
      

      【讨论】:

      • 感谢@RimK 对此解决方案的工作正常 +1
      【解决方案8】:

      如果您以编程方式创建表格视图单元格,则需要将添加子视图添加到 contentView 而不是单元格本身

      【讨论】:

        【解决方案9】:

        斯威夫特 5

        首先创建protocol(delegate)。

        protocol CustomDelegate: AnyObject{
          
          func didSelectedTheButton(_ index: Int)
          
        }
        

        创建UITableViewCell 并将protocol 初始化为实例。并在您的 TableViewCell 中添加按钮和按钮操作。在按钮 Action 中使用协议(委托)。请找到以下代码以供参考

        class TableViewCell: UITableViewCell {
        
          lazy var button: UIButton! = {
        
            let button = UIButton()
            button.translatesAutoresizingMaskIntoConstraints = false
            button.backgroundColor = .darkGray
            button.setTitleColor(.white, for: .normal)
            button.addTarget(self, action: #selector(didTaped(_:)), for: .touchUpInside)
            button.tag = 1
            button.setTitle("Tap", for: .normal)
            return button
        
          }()
          
          weak var delegate: CustomDelegate?
        
          override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            
            self.contentView.backgroundColor =  .clear
            self.backgroundColor =  .clear
            self.contentView.addSubview(button)
        
            self.button.heightAnchor.constraint(equalToConstant: 60).isActive = true
            self.button.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width * 0.66).isActive = true
            self.button.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor).isActive = true
            self.button.centerYAnchor.constraint(equalTo: self.contentView.centerYAnchor).isActive = true
            
          }
          
          required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
          }
          
          @objc func didTaped(_ sender: UIButton){
        
            //Call the protocol function for receive the action in ViewController
            delegate?.didSelectedTheButton(sender.tag)
            
          }
        
        }
        

        接下来创建UIViewController 并将UITableView 集成到您的ViewController 中。在函数tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 中,将您的视图控制器分配给在UITableViewCell 中初始化的委托

        class SecondViewController: UIViewController {
        
          lazy var tableView: UITableView! = {
              let tableView = UITableView(frame: .zero, style: .grouped)
              tableView.translatesAutoresizingMaskIntoConstraints = false
              tableView.register(TableViewCell.self, forCellReuseIdentifier: String(describing: TableViewCell.self))
              tableView.backgroundColor   =   .white
              tableView.separatorColor    =   .clear
              tableView.delegate          =   self
              tableView.dataSource        =   self
              return tableView
          }()
        
            override func viewDidLoad() {
                super.viewDidLoad()
              
              self.view.backgroundColor = .white
              
              //
              self.view.addSubview(self.tableView)
              
              NSLayoutConstraint.activate([
              
                self.tableView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
                self.tableView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
                self.tableView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
                self.tableView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
        
              ])
        
            }
            
        }
        
        extension SecondViewController: UITableViewDelegate, UITableViewDataSource{
          
          func numberOfSections(in tableView: UITableView) -> Int {
            return 1
          }
          
          func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 10
          }
          
          func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
            let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TableViewCell.self), for: indexPath) as! TableViewCell
            cell.button.tag = indexPath.row
        
            //ViewController Assign for protocol delegate
            cell.delegate = self
        
            cell.button.setTitle("Button \(indexPath.row)", for: .normal)
            return cell
            
          }
          
          func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 100
          }
          
        }
        
        extension SecondViewController: CustomDelegate{
        
          //Received the button action for cell
             /**
                index - contains row value for button selected
             */
          func didSelectedTheButton(_ index: Int) {
        
             // Enter your code here what did you want when the tableViewCell button action
             print(index)
            
          }
          
        }
        

        【讨论】:

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