swiftuitableviewbuttoncelldidselectrowatindexpath

Add button to uitableview cell programmatically


I just want my code to produce a button in every table view cell that has text. When the button is press just have it say hi. Each cell should have a button in it. I want this to be done all and code and do not use the storyboard at all. The class should remain a uiview controller and not be changed.

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private let myArray: NSArray = ["First","Second","Third"]
     var myTableView =  UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()

        myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
        myTableView.dataSource = self
        myTableView.delegate = self
        
        
        
        self.view.addSubview(myTableView)
        myTableView.translatesAutoresizingMaskIntoConstraints = false
        
        
        
        NSLayoutConstraint.activate([

            myTableView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.90),
            myTableView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1),
            myTableView.topAnchor.constraint(equalTo: view.topAnchor),
            myTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),



        ])
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("Num: \(indexPath.row)")
        print("Value: \(myArray[indexPath.row])")
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myArray.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
        cell.textLabel!.text = "\(myArray[indexPath.row])"
        return cell
    }
}

Solution

  • Create a subclass of UITableViewcell -

    class MyCell: UITableViewCell {
        
        var buttonTapCallback: () -> ()  = { }
        
        let button: UIButton = {
            let btn = UIButton()
            btn.setTitle("Button", for: .normal)
            btn.backgroundColor = .systemPink
            btn.titleLabel?.font = UIFont.systemFont(ofSize: 14)
            return btn
        }()
        
        let label: UILabel = {
           let lbl = UILabel()
            lbl.font = UIFont.systemFont(ofSize: 16)
            lbl.textColor = .systemPink
           return lbl
        }()
        
        @objc func didTapButton() {
            buttonTapCallback()
        }
        
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            //Add button
            contentView.addSubview(button)
            button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
            
            //Set constraints as per your requirements
            button.translatesAutoresizingMaskIntoConstraints = false
            button.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
            button.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
            button.widthAnchor.constraint(equalToConstant: 100).isActive = true
            button.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true
            
            //Add label
            contentView.addSubview(label)
            //Set constraints as per your requirements
            label.translatesAutoresizingMaskIntoConstraints = false
            label.leadingAnchor.constraint(equalTo: button.trailingAnchor, constant: 20).isActive = true
            label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
            label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
            label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
    }
    

    Now in your view controller register this cell -

    myTableView.register(MyCell.self, forCellReuseIdentifier: "MyCell")
    

    Now load this cell using cellForRowAt method -

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
            cell.label.text = ""
            cell.buttonTapCallback = {
                cell.label.text = "Hi"
            }
            return cell
        }