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:
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
How to Customize the Background Color of a Uitableviewcell
How to Create a Guid/Uuid Using Ios
How to Use Uivisualeffectview to Blur Image
Send Post Request Using Nsurlsession
Detecting Color of Iphone/Ipad/Ipod Touch
Setting Custom Uitableviewcells Height
Programmatically Open Maps App in iOS 6
Determine If Mkmapview Was Dragged/Moved
How to Get Text/String from Nth Line of Uilabel
Delete Keychain Items When an App Is Uninstalled
Manual Language Selection in an Ios-App (Iphone and Ipad)
How to Validate an E-Mail Address in Swift
Uinavigationbar Custom Back Button Without Title
Get Indexpath of Uitableviewcell on Click of Button from Cell
Ios: How to Change App Language Programmatically Without Restarting the App