Uibutton Action in Table View Cell

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
}

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.

To access Tableview cell in Button action

Try this code:

@objc func userLikeButtonWasTappaed(sender: UIButton){

guard let indexPath = tableView.indexPathForRow(at: sender.convert(sender.frame.origin, to: tableView)) else {
return
}

let cell = tableView.cellForRow(at: indexPath) as? MatchingUsersTVCell
}

And in your cellForRowAt function add the following code:

cell.yourBtn.tag = indexPath.row

cell.yourBtn.addTarget(self, action: #selector(userLikeButtonWasTappaed(sender:)), for: .touchUpInside)

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
}

Swift 3.0 TableView Cell Button

There are two ways you can do it - the cheat's way or the proper way. The proper was is to subclass UITableViewCell, in which case you can hookup outlets in the normal way. The cheat's way is to use each element's tag property. If you set the tag of the button to (say) 1, you can use cell.viewWithTag within cellForRowAt to locate it: As in:

let button = cell.viewWithTag(1) as! UIButton

Be aware that it will search the whole hierarchy below cell, so you need to ensure you don't have multiple subviews with the same tag.

From your question, I'm guessing you want to click the button and have its title changed. The click handler should just reload the tableView row (or whole table if you're lazy like me), and cellForRowAt needs to know what title to show. This state of what to show on the button for each row must be held outside the tableView cell, since cells are reused as you scroll. This means that once the top row scrolls off the screen that same cell might be reused for the (say) 20th row. The code in cellForRowAt needs to completely reset the content of the cell in case it was already used for another row.

Adding some detail from your comment on the question, you never want to avoid reusing cells because this is a very good thing. You might be showing a table of 1,000 rows but only 10 are visible on screen. Reusing cells means iOS can create as few as 10 cells to show your entire table, rather than 1,000. Performance is faster as a result.

How to Handle UIButton in TableviewCell in Objective c?

You should create separate class of type UITableViewCell for your cell

TableViewCell.h

@protocol TableViewCellDelegate 

-(void)selectedButton:(int)button rowNumber:(int)row;

@end

@interface TableViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UITextField *textfield1;
@property (weak, nonatomic) IBOutlet UITextField *textfield2;
@property (weak, nonatomic) IBOutlet UITextField *textfield3;
@property (weak, nonatomic) IBOutlet UIButton *bttn1;
@property (weak, nonatomic) IBOutlet UIButton *bttn2;

@property (nonatomic, weak) id delegate;

-(void)setupView:(int)selectedButton;

@end

TableViewCell.m

#import "TableViewCell.h"

@implementation TableViewCell

- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code

self.textfield1.delegate=self;
self.textfield2.delegate=self;
self.textfield3.delegate=self;
[self.bttn1 addTarget:self action:@selector(button1:) forControlEvents:UIControlEventTouchUpInside];
[self.bttn2 addTarget:self action:@selector(button1:) forControlEvents:UIControlEventTouchUpInside];

}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];

// Configure the view for the selected state
}


- (void)button1:(UIButton *)sender {

if(sender == self.bttn1){

[self.delegate selectedButton:1 rowNumber:(int)self.tag];
}
else if([_bttn2 isHighlighted]==YES){

[self.delegate selectedButton:2 rowNumber:(int)self.tag];
}
}


- (void)setupView:(int)selectedButton {

self.textfield1.text = @"";
self.textfield1.tag = self.tag;
self.textfield1.delegate = self;
self.textfield2.text = @"";
self.textfield2.tag = self.tag+20;
self.textfield2.delegate = self;
self.textfield3.text = @"";
self.textfield3.tag = self.tag+40;
self.textfield3.delegate = self;
[self.bttn1 setTitle:@"" forState:UIControlStateNormal];
[self.bttn2 setTitle:@"" forState:UIControlStateNormal];
if (selectedButton == 1) {

self.bttn1.backgroundColor = [UIColor redColor];
self.bttn2.backgroundColor = [UIColor blueColor];
}else if (selectedButton == 2) {

self.bttn1.backgroundColor = [UIColor blueColor];
self.bttn2.backgroundColor = [UIColor redColor];
}else {
self.bttn1.backgroundColor = [UIColor blueColor];
self.bttn2.backgroundColor = [UIColor blueColor];
}
}

@end

ViewController.m

#import "ViewController.h"
#import "TableViewCell.h"

@interface ViewController ()

@property (nonatomic, strong)NSMutableArray *arrSelectedBtns;
@property (weak, nonatomic) IBOutlet UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

self.tableView.delegate = self;
self.tableView.dataSource = self;
self.arrSelectedBtns = [NSMutableArray array];
for (int i=0; i<10; i++) { //10 respresents number of rows in tableview

[self.arrSelectedBtns addObject:[NSNumber numberWithInt:0]];
}
}


- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellview" forIndexPath:indexPath];
cell.tag = indexPath.row;
cell.delegate = self;

[cell setupView:[[self.arrSelectedBtns objectAtIndex:indexPath.row] intValue]];
return cell;
}

- (void)selectedButton:(int)button rowNumber:(int)row {

[self.arrSelectedBtns insertObject:[NSNumber numberWithInt:button] atIndex:row];
NSIndexPath *indexpath = [NSIndexPath indexPathForRow:row inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[indexpath] withRowAnimation:UITableViewRowAnimationNone];
}

@end

Swift - Adding target to UIButton in UITableView not working

It's a matter of hierarchy, you need to add the buttons to the contentView. If you just add a subview to the view, it goes behind the contentView of the UITableViewCell.

Visually, where the selected one is the contentView of the cell, you can see that the actual button is behind it:
Sample Image

So contentView.addSubview(editButton) and contentView.addSubview(deleteButton) does the job.

How to tap button to open URL with the UIButton in the Table View cells?

Create outlet for the button inside the cell then in cellForRowAt

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

Add this inside the vc

@objc func clicked (_ btn:UIButton) {
UIApplication.shared.open(URL(string:buyLink[btn.tag])!, options: [:], completionHandler: nil)
}


Related Topics



Leave a reply



Submit