Custom table view cell with button - ios

I am using storyboard. I have a table view with 1 Prototype cell, and have four rows in table view. Each cell has a label,image view and a button. Now I want to show different data on next View Controller say(DetailsVc), each time when button is pressed.
Row1- Button click will open DetailsVC with some data.
Row2- Button click will open DetailsVC with different data.
and same process for remaining rows.
Any suggestions.
#implementation DetailsVC
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
EmpEngmntTableViewCell *emp;
if((emp.viewGalleryBtn.tag = 1))
{
NSLog(#"tag num for 1st row is %ld",(long)emp.viewGalleryBtn.tag);
self.title = #"Team Building Session";
}
}

The best is to use a delegate pattern. I added an answer here, you can use it for example.
Here is an example enclosed:
Custom Cell .h Class:
#protocol DetailVCProtocol <NSObject>
-(void)loadDetailScreenWithIndex:(NSInteger)rowIndex;
#end
#property (nonatomic, retain) id<DetailVCProtocol> delegate;
#property (nonatomic, retain) IBOutlet UIButton *btn;
Then Synthesize it in .m file
Add this in m file:
-(IBAction)loadDetails:(id)sender
{
// ..... blah blah
[self.delegate loadDetailScreenWithIndex:btn.tag];
}
The viewcontroller that loads this cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// create cell here
cell.btn.tag = indexPath.row;
cell.delegate = self;
}
-(void)loadDetailScreenWithIndex:(NSInteger)rowIndex
{
// Cretae DetailVC with parameter `rowIndex` to populate data
[self presentViewController:detailVC animated:YES completion:nil];
}

In function - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
use this code
cell.btn.tag = indexPath.row;
[cell.btn addTarget:self action:#selector(btnTpd:) forControlEvents:UIControlEventTouchUpInside];
- (IBAction)btnTpd:(id)sender
{
UIButton *btn = (UIButton *)sender;
\\You can get which button is pressed by btn.tag
\\Here call to next ViewController and pass data
}

In cellForRowAtIndexPath
cell.optionsBtn.tag=indexPath.row;
[cell.optionsBtn addTarget:self action:#selector(showMyOptionBtn:) forControlEvents:UIControlEventTouchUpInside];
-(void)showMyOptionBtn:(UIButton *)sender
{
EventDetailViewController *EventDetail=[[EventDetailViewController alloc]init];
EventDetail.buttonTag=sender.tag;
[self.navigationController pushViewController:EventDetail animated:NO];
}
In EventDetailViewController class
if (self.buttonTag==1) {
// your condation
}
else
{
//your condation
}

Related

How to write action for UIButton which is loaded into tableview as custom cell?

Hi I'm new to iOS Development and i am using Objective C. I have a problem in UITableview.That is, i need to write action for multiple UIButton which is loaded into a tableview(DutiesTableView.m & .h) as a custom cell(BreakTimeCell.m &.h). That tableview(DutiesTableView.m & .h) is loaded into another tableview(ViewController.m&.h, TableName is PersonalTable) as s custom cell using XIB.
[Shift(custom cell),Duties(UITableview),Break Time(UITableview)],[This is my ViewController.m
This is my sample output.When i click on the Break time UIButton it should show UIDatePicker on Main Tableview
Create A button,
UIButton *btnSample = [[UIButton alloc]initWithFrame:CGRectMake(215,10,100,50)];
[btnSample setTitle:#"Button Title" forState:UIControlStateNormal];
[yourView addSubview:btnSample];
Add a action to button
[btnSample addTarget:self action:#selector(your action or method) forControlEvents:UIControlEventTouchUpInside];
You can use delegates to get call back from custom cell to your view controller, for example in the custom cell in your code, BreakTimeCell.h file declare a protocol and add button in BreakTimeCell.xib and give outlet and action to custom cell like below,
#import <UIKit/UIKit.h>
#class BreakTimeCell; //forword declaration
#protocol BreakTimeCellDeleagte<NSObject>
- (void)breakTimeCell:(BreakTimeCell *)cell didTapTheButton:(UIButton *)aButton;
#end
#interface BreakTimeCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *aButton;
#property (weak, nonatomic) id<BreakTimeCellDeleagte> cellDelegate;//this is important
- (IBAction)myButtonAction:(id)sender;
+ (BreakTimeCell *)getBreakTimeCell; //to get the custom cell
#end
and in BreakTimeCell.h file define action for the button
#import "BreakTimeCell.h"
#implementation BreakTimeCell
+ (BreakTimeCell *)getBreakTimeCell {
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:#"BreakTimeCell" owner:self options:NULL];
NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
BreakTimeCell *customCell = nil;
NSObject* nibItem = nil;
while ((nibItem = [nibEnumerator nextObject]) != nil) {
if ([nibItem isKindOfClass:[BreakTimeCell class]]) {
customCell = (BreakTimeCell *)nibItem;
break;
}
}
return customCell;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
//call the delegate method in the button action
- (IBAction)myButtonAction:(id)sender {
if([self.cellDelegate respondsToSelector:#selector(breakTimeCell:didTapTheButton:)])
{
[self.cellDelegate breakTimeCell:self didTapTheButton:sender];
}
}
#end
and in view controller just set the cell delegate to view controller,
#import "ViewController.h"
#import "BreakTimeCell.h"
#interface ViewController ()<UITableViewDelegate, UITableViewDataSource, BreakTimeCellDeleagte>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BreakTimeCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MY_BREAK_CELL"];
if (cell == nil) {
cell = [BreakTimeCell getBreakTimeCell]; //get the cell
}
cell.cellDelegate = self; //set the delegate to controller (self)
return cell;
}
//this is the delegate method called for the button action.
- (void)breakTimeCell:(BreakTimeCell *)cell didTapTheButton:(UIButton *)aButton {
NSIndexPath *indexPath = [self.personalTable indexPathForCell:cell];
NSLog(#"button tapped for index:%ld",(long)indexPath.row);
}
thats it, you will get output like below,
2017-12-13 11:44:24.693161+0530 Test[3082:100133] button tapped for index:3
2017-12-13 11:44:25.177169+0530 Test[3082:100133] button tapped for index:4
2017-12-13 11:44:26.223166+0530 Test[3082:100133] button tapped for index:0
2017-12-13 11:44:27.663060+0530 Test[3082:100133] button tapped for index:1
2017-12-13 11:44:28.495780+0530 Test[3082:100133] button tapped for index:2
Add this in cellForRow
yourButton.tag = indexPath.row;
[yourButton addTarget:self action:#selector(methodName:) forControlEvents:UIControlEventTouchUpInside];
Perform task in below method
- (void)methodName:(id)sender
{
// you can get index of button from sender.tag
}

how to set value to textField through a delegate

i have two view controllers, view controller and tableViewController.
ViewController contains a textField and a button. when the button in viewController is clicked, then TableViewController should start.
in TableViewController, there is a list contains 5 rows, each row contains a string value.
What I am trying to do is, hen the user chooses any row in the list in TableViewController, then ViewController scene should start and the value that the user chose should be displayed in the textfield in ViewController.
to achieve this task, I created a protocol in TableViewController with a required method called valueChoosen: (NSString *) value, and this method is implemented in ViewController, and then I set the value to the textField but, at run time the TextField is empty.
please have look at the code below, and let me know why the value passed to the required method of the protocol can not be set to the textfield, what I am doing wrong;
TableViewController:
#import "TableViewController.h"
#interface TableViewController ()
#property NSArray *tableData;
#end
#implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.tableData = [NSArray arrayWithObjects:#"Android",
#"iOS",
#"swift",
#"objective-c",
#"openCV",nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [self.tableData count];
}
-(UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [self.tableData objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"images.jpg"];
return cell;
}
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
NSLog(#"%#", [self.tableData objectAtIndex:indexPath.row]);
[self performSegueWithIdentifier:#"unwindSegue" sender:NULL];
[self.delegate valueChoosen:[self.tableData
objectAtIndex:indexPath.row]];
}
#end
ViewController:
#import "ViewController.h"
#import "TableViewController.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UITextField
*textFieldDepartment;
#property (strong, nonatomic) IBOutlet UIButton
*buttonSelectFromTableView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a
nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"segueToTableView"]) {
//code
TableViewController *table = segue.destinationViewController;
table.delegate = self;
}
}
-(void) valueChoosen: (NSString *) value {
[_textFieldDepartment setText:value];
NSLog(#"value: %#", value);
}
#end
It maybe because you are setting the textfield text in the viewController which is not being displayed. Try assigning the value to a variable using the delegate function and call the delegate function before performing the unwind segue. And on the viewController try setting the textfield text as the variable whose value was set through delegate method from the viewWillAppear method.
Step 1:
create the unwind action in the viewcontroller you want to unwind it.in your case it is ViewController
- (IBAction)unwindFromModalController:(UIStoryboardSegue *)segue{}
Step 2:
Connect to the unwind Action
Control drag from tableviewcell to the Exit sign.
Select the Action you specified.
Add the Identifier to unwind segue.
Step3
Trigger the segue
in your TableViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
self.selectedText = self.tableData[indexPath.row];
[self performSegueWithIdentifier:#"unwindSegue" sender:self];}
Step 4:
Pass Data
Unwind Action
- (IBAction)unwindFromModalController:(UIStoryboardSegue *)segue{
if ([segue.sourceViewController isKindOfClass:[TableViewController class]]) {
TableViewController *vc = segue.sourceViewController;
if (vc.selectedText) {
[_textFieldDepartment setText:vc.selectedText];}
}
}

How to save button selection on UITableViewCell?

My app has a favourite button, on clicking it is converting into red heart and if I click againg then it is back to gray heart. Its working correct. But problem is reuseIdentifier,After scrolling, button just coming to original state because its resusing cell here.
How can I save selection of button so that they remain selected(if selected)
Code of tableViewCell class(.h file):
#import <UIKit/UIKit.h>
#interface favBTNTableViewCell : UITableViewCell
#property(nonatomic)UIButton *faVbtn;
#end
Code of tableViewCell class(.m file)
#import "favBTNTableViewCell.h"
#implementation favBTNTableViewCell
#synthesize faVbtn;
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
{
self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
faVbtn=[UIButton new];
[faVbtn setFrame:CGRectMake(10, 10, 25, 25)];
[faVbtn setBackgroundImage:[UIImage imageNamed:#"unsel"] forState:UIControlStateNormal];
[faVbtn addTarget:self action:#selector(clickOnfav) forControlEvents:UIControlEventTouchUpInside];
[faVbtn setSelected:YES];
[self.contentView addSubview:faVbtn];
}
return self;
}
-(void)clickOnfav
{
if ([faVbtn isSelected]) {
[faVbtn setBackgroundImage:[UIImage imageNamed:#"sel.jpg"] forState:UIControlStateNormal];
[faVbtn setSelected:NO];
}
else
{
[faVbtn setSelected:YES];
[faVbtn setBackgroundImage:[UIImage imageNamed:#"unsel"] forState:UIControlStateNormal];
}
}
Code of ViewContrller.m
#import "ViewController.h"
#import "favBTNTableViewCell.h"
#interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
{
NSString *ci;
}
#property (strong, nonatomic) IBOutlet UITableView *tv;
#end
#implementation ViewController
-(NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 30;
}
-(UITableViewCell*)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
favBTNTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ci];
if(!cell)
{
cell=[[favBTNTableViewCell alloc]init];
cell.faVbtn.tag=indexPath.row;
}
return cell;
}
- (void)viewDidLoad {
_tv.delegate=self;
_tv.dataSource=self;
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
You need corresponding data source for your cells. For this purpose you can, for example, create one more class and you will use it like an item for data source. Take a look:
#interface DataSourceItem : NSObject
#property (nonatomic, assign) BOOL isFavorite;
#end
#implementation DataSourceItem
#end
Then in view controller's code you need to populate array of data source items and manage your table view depending on this array:
#interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
{
NSString *ci;
}
#property (strong, nonatomic) IBOutlet UITableView *tv;
#property (strong, nonatomic) NSArray *dataSourceArray;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_tv.delegate=self;
_tv.dataSource=self;
NSMutableArray *temp = [NSMutableArray new];
// actually how many rows you table view need to have
for (NSUInteger i = 0; i < 30; i++)
{
[temp addObject:[DataSourceItem new]];
}
self.dataSourceArray = [temp copy];**
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// change dataSource item state
DataSourceItem *item = [self.dataSourceArray objectAtIndex:indexPath.row];
item.isFavorite = !item.isFavorite;
// change cell state
favBTNTableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
cell.faVbtn.selected = item.isFavorite;
}
-(NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dataSource count];
}
-(UITableViewCell*)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
favBTNTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ci];
if(!cell)
{
cell=[[favBTNTableViewCell alloc]init];
cell.faVbtn.tag=indexPath.row;
}
// decision based on data source item state
cell.favBtn.selected = self.dataSource[indexPath.row];
return cell;
}
You can fix it like this:
Implement - (void)layoutSubviews method in your custom cell.
In - (void)layoutSubviews, check button state and then set the
right image on it:
->
- (void)layoutSubviews {
[super layoutSubviews];
UIImage *buttonImage = [faVbtn isSelected] ? [UIImage imageNamed:#"sel.jpg"] : [UIImage imageNamed:#"unsel"];
[faVbtn setBackgroundImage:buttonImage forState:UIControlStateNormal];
}
if you are using custom cell
register class/nib for your tableview in did load
[tblName registerNib:[UINib nibWithNibName:#"customCell" bundle:nil] forCellReuseIdentifier:#"customCell"];
henceforth in datasource method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
customCell *cell =(customCell*) [tableView dequeueReusableCellWithIdentifier:#"customCell" forIndexPath:indexPath];
// your code here
return cell;
}
Do not forget to assign your cell identifier as "customCell" in cell attribute
Happy coding..
you can also check similar ans by me
Iphone: Checkmarks in UITableview get mixed up when scrolling

iOS - Reload element from table view cell

I'd like to implement a "like" functionality in a table view. Each row has a like button and a like counter.
When the user taps "like" the like counter should be increased by one. If the same user taps again, the like counter is decreased by one.
I have implemented this using reloadRowsAtIndexPaths. However, this reloads the whole cell and it is bad in terms of usability.
Would you know a simple mechanism to implement such a functionality? The main requirement is that only the like counter is updated, not the whole cell or table.
Thanks in advance,
Tiago
U don't need to reload a whole cell, simply change the title/image for your like button.
Smth. like this:
#pragma mark - custom table cell
#interface TableCellWithLikeButton : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *userLikeButton;
#end
#implementation TableCellWithLikeButton
#end
#pragma mark - User modal
#interface User:NSObject
#property (assign, nonatomic) BOOL wasLiked;
#property (assign, nonatomic) NSInteger likesCounter;
#end
#implementation User
#end
#implementation VC1
{
IBOutlet UITableView *_tableView;
NSMutableArray *_users;
}
- (id)initWithCoder:(NSCoder*)aDecoder
{
if(self = [super initWithCoder:aDecoder]) {
_users = [NSMutableArray array];
for (int i=0;i<100;i++) {
User *user = [User new];
[_users addObject:user];
}
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _users.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CellWithLikeButton";
TableCellWithLikeButton *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
[cell.userLikeButton addTarget:self action:#selector(changeLikeStatus:) forControlEvents:UIControlEventTouchUpInside];
User *user = _users[indexPath.row];
[cell.userLikeButton setTitle:user.wasLiked?#"Liked":#"Like" forState:UIControlStateNormal];
cell.userLikeButton.tag = indexPath.row;
return cell;
}
- (void)changeLikeStatus:(UIButton *)likeButton
{
User *user = _users[likeButton.tag];
user.likesCounter += user.wasLiked?-1:1;
user.wasLiked = !user.wasLiked;
[likeButton setTitle:user.wasLiked?#"Liked":#"Like" forState:UIControlStateNormal];
}
#end

Remove a UITableViewCells button when clicked

I Have a button within a uitableview cell -
I have set it up to trigger a fmethod when clicked - (the function displays messages and resets the message count).
my code for this method is as follows -
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Define Custom Cells
static NSString *CellCountI =#"CellCount";
UITableViewCell *cell;
feedData *f = [self.HpFeedArray objectAtIndex:indexPath.section];
//Comparison Strings
NSString *count = #"Count";
//If statement Cell Filters
//If Count Cell
if ([f.FeedGroup isEqualToString:count]) {
cell = [tableView dequeueReusableCellWithIdentifier:CellCountI forIndexPath:indexPath];
HP_Header_TableViewCell *hpTC = (HP_Header_TableViewCell *)cell;
hpTC.buttonPressedSelector = #selector(buttonImpMsg);
hpTC.buttonPressedTarget = self;
[hpTC.msgsBtn setTitle: f.FeedTitle forState: UIControlStateNormal];
return hpTC;
}
}
The buttonImpMsg method is as follows -
- (void)buttonImpMsg
{
NSLog(#"Back Button Pressed!");
[self removeBtn];
}
I would like to hide the button when clicked - but I'm not sure how to reference it from the buttonImpMsg method?
Pass the sender to the selector:-
- (void)buttonImpMsg:(id)sender {
[sender removeFromSuperview];
}
You could implement the delegate pattern, IMHO, it's the most proper way.
i think , better will be to make it hidden, if you want to again. – #pawan
I would also hide the button rather than remove it.
Try this implementation to hide the button, you can also do the same thing to hide this one after.
TableViewCell.h:
#import "TableViewCell.h"
#implementation TableViewCell
//.... Connect your action or set selector to this method:
- (IBAction)hideButton:(id)sender
{
UIButton *button = (UIButton *) sender;
// hide the button by using the setter
button.hidden = YES;
//.... Check if the delegate method has been implemented
if ([_delegate respondsToSelector:#selector(hideButton)]) {
[_delegate hideButton];
}
}
#end
TableViewCell.h
//... Declare the delegate:
#protocol CellDelegate <NSObject>
- (void)hideButton;
#end
#interface TableViewCell : UITableViewCell
//... Add a delegate property:
#property (strong, nonatomic) id <CellDelegate> delegate;
#end
ViewController.m:
//... set self a the delegate of your cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
cell.delete = self;
return cell;
}
ViewController.m:
//...
#interface ViewController () <CellDelegate>
//...
//... Implement the delegate method if you need to do stuff on the controller side
- (void)hideButton
{
//do stuff here if needed
}

Resources