UITableCell button touchUpInside with index of cell whos button was clicked - iphone

i have a UITable with UITableCells which look as the following:
[ myLabel myButton ]
[ myLabel myButton ]
[ myLabel myButton ]
[ myLabel myButton ]
I would like my handlerCellButtonClicked to also get a reference to the cell index. How can I get a reference to this index as well when the button is touched?
/** called by table to get the cell needed by the index */
-(UITableViewCell*)tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
...
//init cell
...
//configure the cells custom button handlers
[cell.myButton addTarget:self action:#selector(handlerCellButtonClicked) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
/** handler when the button in the cell is clicked */
- (void)handlerCellButtonClicked{
NSLog(#"cell myButton clicked");
}

Make use of UIButton Tag property.
-(UITableViewCell*)tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//init cell
//configure the cells custom button handlers
cell.myButton.tag = indexPath.row;
[cell.myButton addTarget:self action:#selector(handlerCellButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
/** handler when the button in the cell is clicked */
- (void)handlerCellButtonClicked:(UIButton *)sender
{
NSLog(#"%d cell myButton is clicked", sender.tag);
}

Related

UITableViewCell with custom UIButton

I am trying to create a UITableView with a custom UIButton in each table cell. I implemented like this..
#implementation CouponDetailsCustomTableViewCell
...............
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
[self setBackgroundColor:[UIColor whiteColor]];
CGRect frame = self.contentView.frame;
self.radioButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.radioButton setImage:[UIImage imageNamed:#"radio_blank.png"] forState:UIControlStateNormal];
[self.radioButton setImage:[UIImage imageNamed:#"radio_selected"] forState:UIControlStateSelected];
[self.radioButton setFrame:CGRectMake(16, 10, 29, 29)];
[self.radioButton addTarget:nil action:#selector(radioButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:radioButton];
}
#end
and UITableView Delegate as......
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *COUPON_CELL_ID = #"CouponCell" ;
CouponDetailsCustomTableViewCell * couponCell = (CouponDetailsCustomTableViewCell *) [tableView dequeueReusableCellWithIdentifier:COUPON_CELL_ID];
if (couponCell == nil) {
couponCell = [[[CouponDetailsCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:COUPON_CELL_ID] autorelease];
couponCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
[couponCell.radioButton setSelected:NO];
return couponCell;
}
and the radioButtonPressed method is
-(void)radioButtonPressed:(id) sender
{
[sender setSelected:YES];
}
Now i run the program and a custom UIButton is shown in every table row . If i click on a button it gets selected (shows the radio_selected.png).
The problem arises when i scroll down the table (i am showing only 4 rows of the table in the window) . When i scroll up again..what i see is the clicked button is showing the radio_blank.png.
I am new in iPhone development. i dont know why is this happening. The most i can guess is the button property is changing .. setSelected:NO.
Someone please give me suggestions to fix this problem.
Thank you.
When you scroll your UITableView, hidden cells are not rendered anymore and might be reused for cells that are becoming visible. If a new cell becomes visible, tableView:cellForRowAtIndexPath: gets called.
The problem is that you're setting the selected state there:
[couponCell.radioButton setSelected:NO];
Therefore, whenever you scroll your cell out of the visible area and back again, it gets reset to selected = NO.
I suggest you create a NSMutableDictionary where you store the selection state of each row/NSIndexPath, which you then re-apply in tableView:cellForRowAtIndexPath:.
replace [couponCell.radioButton setSelected:NO]; in tableView:cellForRowAtIndexPath: with code that sets the selected property depending on a state from your dataSource.
something along those lines:
/* get the button state from your data source */
FancyCouponObject *coupon = [self.coupons objectAtIndex:indexPath.row];
BOOL buttonState = coupon.buttonState;
[couponCell.radioButton setSelected:buttonState];
The cells of a tableView are reused when they are moved off screen. You can't save state in them.
problem is when you scroll the table at that time your cellForRowAtIndexPath: delegate method called for every row... so here when its called at time your setSelected Method call with NO argument like bellow...
[couponCell.radioButton setSelected:NO];
so when you scroll table at time your setSelected method call and your button turn with radio_blank.png
...
:)
-(void)radioButtonPressed:(id) sender
{
[sender setSelected:YES];
}
in this method you are setting button as selected and for selected button you have set the radio_blank.png image

Not getting action when pressing UIButton inside a custom static cell

Using iOS5. I dragged a UIButton object to inside a custom static cell. Since I am not using dynamic properties I am not using the data source template. The thing is that I am unable to trigger any event when pressing that UIButton inside the cell. I am running the folioing code in my table view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
NSIndexPath *myIP = [NSIndexPath indexPathForRow:1 inSection:1];
UITableViewCell *cell = [medicareTableView cellForRowAtIndexPath:myIP];
UIButton *stepNumberOfChildren = (UIButton *)[cell viewWithTag:222];
[stepNumberOfChildren addTarget:self action:#selector(dontTouchMe:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)dontTouchMe:(id)sender {
NSLog(#"Touched Button %i",((UIButton *)sender).tag);
}
Run the app, press the UIButton and it does not log anything... What am I doing wrong?
Connect your outlet to dontTouchMe function (TouchUpInside)
I hope you want to add the target only to the cell at row=1 and section=1
So code as follows,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexpath.row==1&&indexpath.section==1)
{
//add the button target
}
}

Getting a button press from a custom UITableViewCell's button

I have a project with a custom UITableViewCell (cell.h/.m/.xib) that has 2 labels (labelMain/labelSub), and 2 buttons on it (buttonName/buttonInfo) linked to 2 actions (showName/showInfo).
What I want to do is be able to access the 2 actions in my projects main viewcontroller so that when showName is pressed, a textfield.text in the viewcontroller (not in the cell) is set to that specific cell's labelMain.text.
Hope that makes sense. My problem is that if I write the action (showName) in the cell.m, I cannot access the textfield from my main viewcontroller. On the flip side, if I write the action in my viewcontroller, how do I know which button inside which cell was tapped?
Hope this makes sense...
Use tag can identify which button in which cell is being tapped.
- (UITableViewCell *)tableView:(UITableView *)tableViews cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//init identifier
if (cell ==nil)
{
//load nib file
}
buttonName.tag = indexPath.row;
[buttonName addTarget:self action:#selector(showName:) forControlEvents:UIControlEventTouchUpInside];
buttonInfo.tag = indexPath.row;
[buttonInfo addTarget:self action:#selector(showInfo:) forControlEvents:UIControlEventTouchUpInside];
}
}
-(void) showName:(UIButton*)button{
int row = button.tag; //you know that which row button is tapped
}
-(void)showInfo:(UIButton*)button{
int row = button.tag;//you know that which row button is tapped
}
---------------- EDIT -------------
If you need to know which button is pressed based on row & section, you may try this below. (in cellForRowAtIndexPath: method)
int tag = (indexPath.row+1)+(indexPath.section*100);
buttonName.tag = tag;
When button at
row = 5, section = 0 then tag = 6.
row = 4, section = 3 then tag = 305.
row = 0, section = 11 then tag =1101.
limitation, row cannot be more than 99. and DON'T use positive tag for other view. if you need use tag, try negative. (-1, -9, -100).
so from here, you can calculate back row & section of indexPath. using this :
-(NSIndexPath*)getIndexPathFromTag:(NSInteger)tag{
/* To get indexPath from textfeidl tag,
TextField tag set = (indexPath.row +1) + (indexPath.section*100) */
int row =0;
int section =0;
for (int i =100; i<tag; i=i+100) {
section++;
}
row = tag - (section*100);
row-=1;
return [NSIndexPath indexPathForRow:row inSection:section];
}
how to use :
-(void)showInfo:(UIButton*)button{
NSIndexPath *indexPath = [self getIndexPathFromTag:button.tag];
int row = indexPath.row;
int section = indexPath.section;
}
Try this in viewController.m file in cellForRowAtIndexPath method
[[customCell showNameBtn] setTag:indexPath.row];
[[customCell showNameBtn] addTarget:self action:#selector(showName:) forControlEvents:UIControlEventTouchDown];
-(void) showName:(id)sender
{
// check here the sender tag and then perform you action what you want.
}
I suggest to use delegate(protocol) method for this. You will be having full control on the button, cell and the view controller. And its very simple too
The simplest solution in my opinion:
In your CustomCell.h :
#property (nonatomic, copy) void (^buttonTapAction)(id sender);
In your CustomCell.m create the IBAction and connect it to your UIButton :
-(IBAction)cellButtonIsPressed:(id)sender{
if (self.buttonTapAction) {
self.buttonTapAction(sender);
}
}
Then in the ViewController.m where your UITableView is managed :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString* cellIdentifier = #"customCell";
CustomCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell.buttonTapAction = ^(id sender){
//Do what you want to do when the button inside THIS cell is clicked
};
}
Try to create the button dynamically, with its methods in same controller. Do this in cellForRowAtIndexPath: method:
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"WorkRequestedCC" owner:self options:nil];
{
for (id oneObject in nib) if ([oneObject isKindOfClass:[WorkRequestedCC class]])
cell = (WorkRequestedCC *)oneObject;
}
UILabel *costLbl=[[UILabel alloc]initWithFrame:CGRectMake(792, 13, 10, 15)];
costLbl.text=#"$";
[costLbl setBackgroundColor:[UIColor clearColor]];
UITextField *txtCost=[[UITextField alloc]initWithFrame:CGRectMake(805, 10, 94, 27)];
txtCost.backgroundColor=[UIColor whiteColor];
[txtCost setKeyboardType:UIKeyboardTypeNumberPad];
txtCost.text=obj.expCost;
[txtCost addTarget:self action:#selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
[cell.contentView addSubview:costLbl];
[cell.contentView addSubview:txtCost];
cell.lblDes.text=obj.expDes;
}
- (void)textChanged
{
//your code here
}

addTarget:action:forControlEvents: from a UITableViewCell

I have a UITableViewCell with 3 checkmark buttons. Each checkmark button is a custom UIButton (just the images really), and have an outlet in the custom UITableViewCell subclass. In the cellForRowAtIndexPath method, I
[cell.firstcheckmark addTarget:self action:#selector(checkmarkPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.secondcheckmark addTarget:self action:#selector(checkmarkPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.thirdcheckmark addTarget:self action:#selector(checkmarkPressed:) forControlEvents:UIControlEventTouchUpInside];
- (void)checkmarkPressed:(id)sender {
// how do I get which checkmark was pressed?
}
I was not sure how to get which button was pressed from the sender object. Other times I can use the title of the button, but in this case, all the buttons are the same except their outlet. How do I get which button was pressed? Or do they each need to call a different method, and then in each of those three methods, I can update my model by calling the same modelUpdateMethod: from each of those three methods? Thanks.
You can identify them by their tag:
cell.firstcheckmark.tag = 0;
And then
- (void)checkmarkPressed:(id)sender {
UIButton *button = (UIButton*)sender;
if(button.tag == 0)
{
...
}
...
}
i think you can also use :
UITableViewCell *cell = (UITableViewCell *)[[sender superview] superview];
it can get which cell the button in.

iPhone:How to get the button action of a customcell from the viewcontroller?

I use UITableview, using IB I defined a UIButton in a custom cell and some labels, The custom cell subclass already have definitions of IBAction of the button and necessary IBOutlets on it, but I want to handle the button click events in the tableview controller it self but not in the custom cell subclass.
How can I do this? also I need to get which row's button is exactly clicked so I will show the content relavant to it.
I solved problem by addding this into my controller;
[cell.expButton setTag:indexPath.row];
UIButton *button = (UIButton *)[cell expButton];
[button addTarget:self action:#selector(buttonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
For the need of clickable event(touch effect on the subView), I usually do this :
-(void)viewDidLoad{
self.tableView.delaysContentTouches = NO;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// This will do the touch down effect on the subView of your UIButton
for (id obj in cell.subviews)
{
if ([NSStringFromClass([obj class]) isEqualToString:#"UITableViewCellScrollView"])
{
UIScrollView *scroll = (UIScrollView *) obj;
scroll.delaysContentTouches = NO;
break;
}
}
// I need to get which row's button is exactly clicked so I will show the content relavant to it.- here it is
UIButton *btn = (UIButton*)[cell viewWithTag:200];
// btn = cell.myButton; If you are connected with the IBOutlet
[btn setTag:200 + indexPath.row];
[self.btnPlay addTarget:self action:#selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)btnAction: (id)sender{
UIButton *btn = (UIButton *)sender;
NSLog(#"Selected subView of the Row is %d th tag", btn.tag-200);
// You can get the UITableViewCell using the tag property
selectedIP = [NSIndexPath indexPathForRow:btn.tag - 200 inSection:1;
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:selectedIP];
// Do the relevant code
}
the way how you want to do this is right (how MVC have to coded clean) - thats beautiful!
To make it more efficent you have to use delegation - thats the best way how to do this!
Here a way how you can do this (e.g. in swift).
https://stackoverflow.com/a/29920564/1415713