How to add a button with click event on UITableViewCell in Swift?
Popular patterns for solving this problem are closures and delegates.
If you want to use closures, you would do something like this:
final class MyCell: UITableViewCell {
var actionBlock: (() -> Void)? = nil
then
@IBAction func didTapButton(sender: UIButton) {
actionBlock?()
}
then in your tableview delegate:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - > UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellIdentifier") as? MyCell
cell?.actionBlock = {
//Do whatever you want to do when the button is tapped here
}
A popular alternative is to use the delegate pattern:
protocol MyCellDelegate: class {
func didTapButtonInCell(_ cell: MyCell)
}
final class MyCell: UITableViewCell {
weak var delegate: MyCellDelegate?
then
@IBAction func didTapButton(sender: UIButton) {
delegate?.didTapButtonInCell(self)
}
..
Now in your view controller:
then in your tableview delegate:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - > UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellIdentifier") as? MyCell
cell?.delegate = self
And add conformance to the protocol like this:
extension MyViewController: MyCellDelegate {
didTapButtonInCell(_ cell: MyCell) {
//Do whatever you want to do when the button is tapped here
}
}
Hope this helps!
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
}
how to distinguish button in tableviewcell click event and tableviewcell click event
I had thought the issue was caused by the layer sequence. Then with the help of @AndreaMugnaini, @FahriAzimov, @MilanNosáľ, I know the layer sequence was not the issue.
Then I think it may caused by the layout. So I check the constraints, I find there is one extra constraint. I removed the 8.5 constraint, it works well.
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.
Swift - Clicked button inside tableview cell does not call the did select row at function of that cell
Button action won't call the didSelectRowAt
. You should go for delegate method. If not aware about delegate means refer this
Get button click inside UITableViewCell
1) In your cellForRowAtIndexPath:
method, assign button tag as index:
cell.yourbutton.tag = indexPath.row;
2) Add target and action for your button as below:
[cell.yourbutton addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
3) Code actions based on index as below in ViewControler
:
-(void)yourButtonClicked:(UIButton*)sender
{
if (sender.tag == 0)
{
// Your code here
}
}
Updates for multiple Section:
You can check this link to detect button click in table view for multiple row and section.
Related Topics
How to Hide "-" (Delete) Button While Editing Uitableview
How to Call a View Controller Programmatically
How to Get Core Data Object from Specific Object Id
How to Create Border in Uibutton
Locking a Uisearchbar to the Top of a Uitableview Like Game Center
Uikeyboardboundsuserinfokey Is Deprecated, What to Use Instead
Linking Child View Controllers to a Parent View Controller Within Storyboard
Back Button Callback in Navigationcontroller in iOS
Why Is There an Frame Rectangle and an Bounds Rectangle in an Uiview
What Exactly Is Init Coder Adecoder
iOS - 'Myproject-Swift.H' File Not Found When Running Unit Tests for Swift
iPhone Sdk Internet Connection Detection
Find Current Country from iPhone Device
How to Get Hour and Minutes from Nsdate
Xcode 8 Custom Font Doesn't Show Up in Interface Builder