I currently have a button defined in a cell and a method to track its UITouchDown action as shown:
- (void) clickedCallSign:(id)sender {
int index = [sender tag];
NSLog(#"event triggered %#",index);
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
//Callsign button
UIButton *button;
CGRect rect = CGRectMake(TEXT_OFFSET_X, BORDER_WIDTH, LABEL_WIDTH, LABEL_HEIGHT);
button = [[UIButton alloc] initWithFrame:rect];
cell.tag=[indexPath row];
button.tag=[indexPath row];
[button addTarget:self action:#selector(clickedCallSign:) forControlEvents:UIControlEventTouchDown];
[button setBackgroundColor:[UIColor redColor]];
[button setTitle:#"hello" forState:UIControlStateNormal];
[cell.contentView addSubview:button];
[button release];
}
However when I click a cell in the simulator, the console debug message is: "event triggered (null)" and my app crashes shortly after.
How can I correctly get the indexPath.row value into my clickedCallSign method?
First off, index is an int, so your NSLog needs to look like this (note the %d):
NSLog(#"event triggered %d", index);
(It's possible that this leads to a crash, but it's also likely that something else entirely is going that causes the instability.)
Tag is good until you haven't both sections and rows. Try another way to get index path:
- (void)tableView:(UITableView*)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath*)indexPath {
//...
[button addTarget:self action:#selector(clickedCallSign:withEvent:) forControlEvents:UIControlEventTouchDown];
//...
}
// Get the index path of the cell, where the button was pressed
- (NSIndexPath*)indexPathForEvent:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
return [self.tableView indexPathForRowAtPoint:currentTouchPosition];
}
- (IBAction)clickedCallSign:(id)sender withEvent:(UIEvent*)event
{
NSIndexPath* buttonIndexPath = [self indexPathForEvent:event];
}
If you don't want to use the tag field, have the button invoke this method:
- (void)tapAccessoryButton:(UIButton *)sender
{
UIView *parentView = sender.superview;
// the loop should take care of any changes in the view heirarchy, whether from
// changes we make or apple makes.
while (![parentView.class isSubclassOfClass:UITableViewCell.class])
parentView = parentView.superview;
if ([parentView.class isSubclassOfClass:UITableViewCell.class]) {
UITableViewCell *cell = (UITableViewCell *) parentView;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[self tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
}
}
Related
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Replace action of swipe to delete by clicking on a button
I have the following code.
- (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editingStyle forRowAtIndexPath: (NSIndexPath *) indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[appointments removeObjectAtIndex: indexPath.row]; // manipulate your data structure.
[tableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath]
withRowAnimation: UITableViewRowAnimationFade];
NSLog(#"row deleted"); // Do whatever other UI updating you need to do.
}
}
This piece of code is going to be execute when I swipe on the cell. But what I want is that this code executes when I press a button in my custom tableview cell. Like you can see on the screenshot below I have 2 buttons on my tableview.
When the user presses the 'X' button the delete button should roll out like when you swipe the cell. I have the following action attached to my cell.
-(IBAction) deleteAppointment:(id) sender{
//show swipe delete button
}
And attached it in my cellForRowAtIndex at the following way.
cell.deleteAppointment.tag = indexPath.row;
[cell.deleteAppointment addTarget:self action:#selector(deleteAppointment:) forControlEvents:UIControlEventTouchUpInside];
just addTarget with button in your cell and set tag to every button like bellow..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
/////your code
UIButton *btnClose = [[UIButton alloc]initWithFrame:CGRectMake(270, 7, 20, 20)];
btnClose.tag = indexPath.row;
[btnClose setImage:[UIImage imageNamed:#"closeImage.png"] forState:UIControlStateNormal];
[btnClose addTarget:self action:#selector(deleteAppointment:) forControlEvents:UIControlStateNormal];
[cell addSubview:btnClose];
return cell;
}
and in the method see like this...
- (IBAction)deleteAppointment:(id)sender {
// here bellow code for swipe the close button in cell
UIButton *btn = (UIButton *)sender;
int SelectedRowNo = btn.tag;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[btn setFrame:CGRectMake(btn.frame.origin.x - 50, btn.frame.origin.y, btn.frame.size.width, btn.frame.size.height)];
[UIView commitAnimations];
//// here bellow code for delete raw from table
/*
[appointments removeObjectAtIndex: SelectedRowNo];
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonPath = [yourTableView indexPathForCell:clickedCell];
[yourTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: clickedButtonPath]
withRowAnimation: UITableViewRowAnimationFade];
NSLog(#"row deleted"); // Do whatever other UI updating you need to do.
*/
}
i hope this help you..
I have a UITableview that I'm displaying some tasks and each row has a checkbox to mark tasks complete or not.
I'm looking to toggle the checkmark when the user taps on the checkbox, and switch to a detailed view when the user taps on the row. The latter is easy, just by using
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
However, I wanted to separate the selection areas, toggling only the checkbox when the accessoryview is selected, and going into detailed view only when the rest of the cell is selected. If I add a UIbutton inside the accessoryview, the user would be selecting the row AND the UIButton when they only wanted to hit the checkbox, right?
Also, what if the user was just scrolling through the tableview by dragging along the accessoryview? Wouldn't this trigger an action on the UIButton on TouchUp?
Anyone have any ideas on how to do this? Thanks for your time!
How about managing accessory taps inside this delegate method:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
EDIT:
You can do something like this for custom accessoryView that responds to accessoryButtonTappedForRowWithIndexPath: method.
In cellForRowAtIndexPath: Method -
BOOL checked = [[item objectForKey:#"checked"] boolValue];
UIImage *image = (checked) ? [UIImage imageNamed:#"checked.png"] : [UIImage imageNamed:#"unchecked.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame;
[button setBackgroundImage:image forState:UIControlStateNormal];
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
if (indexPath != nil)
{
[self tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
NSMutableDictionary *item = [dataArray objectAtIndex:indexPath.row];
BOOL checked = [[item objectForKey:#"checked"] boolValue];
[item setObject:[NSNumber numberWithBool:!checked] forKey:#"checked"];
UITableViewCell *cell = [item objectForKey:#"cell"];
UIButton *button = (UIButton *)cell.accessoryView;
UIImage *newImage = (checked) ? [UIImage imageNamed:#"unchecked.png"] : [UIImage imageNamed:#"checked.png"];
[button setBackgroundImage:newImage forState:UIControlStateNormal];
}
i have a table view, in one condition i want to use an accessory using UITableViewCellAccessoryDetailDisclosureButton, but i want to change that icon with my icon, can i do it??
yes ....you can do it easily by adding custom button...
Create the Custom button,
Setting the image of button
Add this button to accessoryView
Set the method for the button
I am providing you some help with the Code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell =(Custom *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[Custom alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
[cell setBackgroundColor:[UIColor clearColor]];
menuTable.separatorColor =[UIColor clearColor];
}
UIImage *image = [UIImage imageNamed:#"ButtonClickOrder.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame; // match the button's size with the image size
//[button setBackgroundImage:image forState:UIControlStateNormal];
[button setImage:image forState:UIControlStateNormal];
// set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
return cell;
}
//These are the methods which are called with the AccessoryView is Clicked
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:menuTable];
NSIndexPath *indexPath = [menuTable indexPathForRowAtPoint: currentTouchPosition];
NSLog(#"Section:%d",indexPath.section);
NSLog(#"Index:%d",indexPath.row);
if (indexPath != nil)
{
[ self tableView: menuTable accessoryButtonTappedForRowWithIndexPath: indexPath];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%d",indexPath.section);
}
Hope this will surely work for u....
I have this code on my cellForRowAtindexPath, with a custom cell and a button on the each cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"tblCellView";
TableCellView *cell = (TableCellView *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
Alarms *alarma = (Alarms *)[alarmsArray objectAtIndex: indexPath.row];
if (!cell) {
[[NSBundle mainBundle] loadNibNamed:#"TableCellView" owner:self options:nil];
cell = tblCell;
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(-7, 4, 30, 33)];
[button addTarget:self action:#selector(favButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[button setTag:1];
[cell.contentView addSubview:button];
[button release];
}
// Set up the cell.
[cell setLabelText: [alarma nombreAlarma]];
UIButton *button = (UIButton *)[cell viewWithTag:1];
button.tag = indexPath.row;
return cell;
}
My problem is that when I click on the button, I got random results, as soon as I move on the table and cells are reusing I got different indexes that are not equal to label tex for the cell in question.
-(IBAction)favButtonAction: (id)sender
{
UIButton *button = (UIButton *)sender;
Alarms *alarma = (Alarms *)[alarmsArray objectAtIndex: button.tag];
NSLog(#"labelText: %#",[alarma nombreAlarma]);
}
for example, the first cell always is ok but the last cell is equal to first objectAtIndex (maybe button.tag is equal to 0 when it must be 14?)
Ok I found a solution, is a different approach but it works :
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
and then on the button handler:
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
if (indexPath != nil)
{
...
}
}
more info here Detecting which UIButton was pressed in a UITableView
Don't put tag value for button inside cell.
This is my button inside the content view of my cell. Note: button should be subview of Contentview.
[cell1.YourButton addTarget:self action:#selector(OnClickCategory:) forControlEvents:UIControlEventTouchUpInside];
Action for my button
- (void) OnClickCategory:(id) sender {
//NSIndexPath *indexPath =(NSIndexPath *)[sender tag];
UIView *senderButton = (UIView*) sender;
NSIndexPath *indexPath = [CategoryTable indexPathForCell: (UITableViewCell*)[[senderButton superview]superview]];
NSLog(#"%d",indexPath.row);
}
This works for me.
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(230.0f, 4.0f, 60.0f, 36.0f);
[btn setTitle:#"OK" forState:UIControlStateNormal];
[btn setTitle:#"OK" forState:UIControlStateSelected];
[btn addTarget:self action:#selector(onClickRename:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:btn];
return cell;
}
but if the user selects the button on particular row, i can change that image through onClickRename...but can i get inwhich row's image has been touched through
(void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath)indexPath ?
you could do something like
[btn setTag:[indexPath] row]
in your cell setup, and then
- (void) onClickRename:(id)sender {
int row = sender.tag;
}
you'd know which table row was hit.
Apple uses the following technique in their Accessory sample code:
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
if (indexPath != nil)
{
// do what you want with the item at indexPath
}
}
In Swift, you can set a tag for each button
Also, set each index value as its tag, we get to know which button is clicked at which row.
to set tag, in cellForAtIndexPath
cell.button.tag = indexPath.row
in button Action
#IBAction func anAction(_sender : AnyObject){
let tappedButton = sender.tag // gives the row and button
}