Uitableviewcell Buttons with Action

UITableViewCell Buttons with action

I was resolving this using a cell delegate method within UITableViewCell's subclass.

Quick overview:

1) Create a protocol

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

2) Subclass your UITableViewCell (if you haven't done so):

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) Let your view controller conform to YourCellDelegate protocol that was implemented above.

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

4) Set a delegate, after the cell has been defined (for reusing).

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

5) In the same controller (where is your implemented UITableView delegate/datasource), put a method from YourCellDelegate protocol.

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

Now, your solution is not tag / number dependent. You can add as many buttons as you want, so you are ready to get response via delegate regardless how many buttons you want to install.

This protocol-delegate solution is preferred in iOS logic and it can be used for other elements in table cell, like UISwitch, UIStepper, and so on.

UIButton action in table view cell

Swift 4 & Swift 5:

You need to add target for that button.

myButton.addTarget(self, action: #selector(connected(sender:)), for: .touchUpInside)

And of course you need to set tag of that button since you are using it.

myButton.tag = indexPath.row

You can achieve this by subclassing UITableViewCell. Use it in interface builder, drop a button on that cell, connect it via outlet and there you go.

To get the tag in the connected function:

@objc func connected(sender: UIButton){
let buttonTag = sender.tag
}

Button action in custom UITableViewCell affects other cells

This is occurring due to UITableview have reusablecell policy.In order to resolve this issue You need to maintain one array of selected items in cellForRowAtIndexPath method you have to verify weather this button is being hold by selected item array. if yes then apply selection styles otherwise apply normal style to it.

Check below source code for buttonclick:

func GetUpdatesButton(sender: UIButton) 
{
var sen: UIButton = sender
var g : NSIndexPath = NSIndexPath(forRow: sen.tag, inSection: 0)
var t : CustomCell = self.myTableView.cellForRowAtIndexPath(g) as! CustomCell
t.btnGetUpdates.backgroundColor = UIColor.redColor()
self.selectedButtonsArray.addObject(indexpath.row)
}

Below code for applying styles on buttons in CellForRowAtIndexPath:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : CustomCell
cell = tableView.dequeueReusableCellWithIdentifier("CustomCellID", forIndexPath: indexPath) as! CustomCell
cell.strName.text = self.names[indexPath.row]
cell.imgPerson.image = UIImage(named: "\(self.persons[indexPath.row])")!

if(self.selectedButtonsArray.containsObject(indexpath.row)){

cell.btnGetUpdates.backgroundColor = UIColor.redColor()
cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
cell.btnGetUpdates.layer.borderWidth = 1
cell.btnGetUpdates.layer.cornerRadius = 5.0

}else{

cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
cell.btnGetUpdates.layer.borderWidth = 1
cell.btnGetUpdates.layer.cornerRadius = 5.0

}

cell.btnComment.layer.borderColor = UIColor.darkGrayColor().CGColor
cell.btnComment.layer.borderWidth = 1
cell.btnComment.layer.cornerRadius = 5.0

cell.btnReadMore.layer.borderColor = UIColor.darkGrayColor().CGColor
cell.btnReadMore.layer.borderWidth = 1
cell.btnReadMore.layer.cornerRadius = 5.0

cell.dateMissingPersonPlace.text = self.MissingPeoplePlace[indexPath.row]
cell.dateMissingPersonSince.text = self.MissingPeopleSince[indexPath.row]

cell.btnGetUpdates.tag = indexPath.row
cell.btnGetUpdates.addTarget(self, action: "GetUpdatesButton:",forControlEvents: .TouchUpInside)

return cell

}

I hope this helps to resolve your problem! Thanks.

Add button to uitableview cell programmatically

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
}

Button Action from UITableViewCell to ViewController

You should set the delegate of your cell in the cellForRowAtIndexPath method.As @vadian said,In the viewDidLoad you should not initialize your cell using default initializer, and the delegate is nil for your cell by this way in viewDidLoad.

Either initialise your cell using the init(style: reuseIdentifier) or set the delegate in the cell for row method as you will initialize the cell in that method anyway.



Related Topics



Leave a reply



Submit