Passing a value on a IBAction button method in a UITableview Row - iphone

I have a value called member id and I want to send it to another view controller, If I place the following in didSelectRowAtIndexPath, The value passes to the variable "member".
int memberIndex = [indexPath indexAtPosition: [indexPath length] - 1];
member = [[tableDataSource2 objectAtIndex: memberIndex] objectForKey:#"Memberid"];
If it is placed in the cellForRow, of course it rewrites with every row created. I have a button in each row that launches a viewController, I want the button action to grab the rows "member" and pass it to the new controller. Is there a "didSelectButton at index path method" or a way to grab that on the fly?
any Ideas would be great. It's the first time I'm adding a button to a UiTableview.
Thanks

Why not use the accessory view? It is a built-in button that you can skin with any image you want to give the UI any kind of feel that is required. Then add this to the table's delegate:
accessoryButtonTappedForRowWithIndexPath: (NSIndexPath *) indexPath{ ... }
You will then be able to call your method on your table data source and launch your secondary view.

Just play with "tag".
Each UIView has an attribute tag (int).
in the cellForRowAtIndexPath :
//create yourButton and then
yourButton.tag = memberIndex;
and when you are using an IBAction just get the sender :
- (IBAction) didSelectButton:(id)sender
{
int memberIndex = ((UIButton *)sender).tag;
//
}
tips : to get the sender when you are setting the action property of your button don't forget the ":"
E.G
action = #selector(didSelectButton:);

Related

Getting the data of a particular row with a button infront of it and passing that data to the clickButton function

I am currently in the cellForRow method where I have a button infront of each row.
CellForRow:
JSONDecoder *decoder=[[JSONDecoder alloc] initWithParseOptions:JKParseOptionNone];
NSMutableArray *json=[decoder objectWithData:myData]; {This has a list of items in the dictionary format}
NSDictionary *dict=[json objectAtIndex:indexPath.row];
NSString *status=[dict valueForKey:#"status key in json"];
"dict" can be represented as:
{
status key in json="approved";
name="abc";
type="resourceName";
},
{
status key in json="rejected";
name="xyz";
type="bus";
},
{
status key in json ="pending";
name="pqr";
type="resource";
}...and so on .
Printing status will give me the status of all the rows.
approved
rejected
pending
But I only need the status of that particular row infront of which I am gonna click the button. This is because I need that status for each row separately to send it to the buttonPressed method when I click the button infront of that row. I don't want to do that in didSelectRow method.
How can I get the indexPath.row of a particular row(on clicking that row) so that I could write the method on click of the button corresponding to that particular row?
You just have to add the button as subview for your cell, and pass indexpath.row as a button tag.Thats it.
I have given the sample
//Create ur cell then do the following
UIButton *objBtn=[UIButton buttonWithType:UIButtonTypeCustom];
[objBtn setFrame:CGRectMake(100,5,50,50)];
[objBtn addTarget:self action:#selector(methodWhichGetsCallOnButtonClick:)forControlEvents:UIControlEventTouchUpInside];
objBtn.tag = indexPath.row;
[cell addSubview:objBtn];
Now in "methodWhichGetsCallOnButtonClick" method add your business logic.
Also take a look on this question.
EDIT:
Also See this link
Try this out, and revert me back if need any more help.
If I am not wrong you want indexPath of cell on button clicked.You can get the cell of that button(in button action) as follows:
UIButton *theButton = sender;
CreatedCell *cell = (CreatedCell *)[[theButton superview] superview];
After getting cell, you can get indexPath of that cell as follows:
theIndexPath = [[m_TableView indexPathForCell:cell] retain];
You can use tag to UIButton.
In cellForRowAtIndexPath Method
You set tag to Button like this
btn.tag=indexpath.row;
In Button Action method you can retrive tag value using this line
Action method for Button
-(void)btnAction:(id)sender
{
UIButton *btn=(UIButton *) sender;
int tagValue=btn.tag;
NSDictionary *dict=[json objectAtIndex:tagValue];
// From this dictionory you cann acces the stauts key value
}
I hope it works for you

How to implement custom cell selection behavior with button for UITableViewController?

I'm trying to replace standard table cell selection behavior with a button-press behavior. The result should be same - to push detailViewController on top and to present some detail info. The cell view is loaded from a separate xib file. So, I need to put a button in that cell xib and use that button for opening detail VC in table VC. I have placed the button view in cell xib, and disabled cell selection in table VC viewDidLoad, but now, I'm not sure how to handle that button press, where to place the button press code or what delegate method to use because didSelectRowAtIndexPath is not respoding (cos I disabled it). Any suggestions?
UPDATE: I need to get some info from cell (section, index) on button press in order to initialize the data for detail VC. Also, should note, that there will be several buttons in each cell.
UPDATE2: I'm using rows with sections, so on button press I need to pass both section and row numbers that corresponds to cell where the button was pressed.
UPDATE3: I have tried to use unique tags for identifying cells but it looks like it's not the solution because I'm getting problems with cell reusing. The first 9 rows are created and relevant tag number are set to them. But then every row from 10 is reused from the queue, so I get the same 9 view with their tags. For example, 10th row pops me the first row button from the queue with the tag 1, 11th - second row button with tag 2 and so on. I mean, the whole dequeue cells means that it doesn't matter how much rows do you have in table, there will be reused 9 cell views for all of the table rows. That means I cannot assign unique tags for the cells because the cell views are not unique for each row
If i got u r question right then this will be solution
[cell.yourButton addTarget:self action:#selector(myAction:) forControlEvents:UIControlEventTouchUpInside];
//you can use tag property of button
NSUInteger tag=indexPath.row+1;
cell.yourButton.tag=tag;
this code should be in
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
& you write action as
-(IBAction)myAction:(id)sender{
UIButton *but=(UIButton *)sender;
NSLog(#"Tag-%d",but.tag);
NSUInteger index=but.tag-1;
//using tag you will come to know which button is pressed ...
}
The suggestions with tags didn't worked out because of a reason described in UPDATE3. However, I did succeed by calling "magic" indexPathForRowAtPoint: method. So the solutions is:
1) attach custom method for button press in cellForRowAtIndexPath:
// I have already created/loaded and got a handler to my button btn
// here comes attaching
[btn addTarget:self action:#selector(openDetailViewController:event:) forControlEvents:UIControlEventTouchUpInside];
2) Define custom method:
-(void)openDetailViewController:(id)sender event:(UIEvent *)event{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:currentTouchPosition];
// do my stuff
}
So, when the button gets pressed my method gets called, passing some additional parameter like event. By calling "allTouches" and "anyObject" I'm getting the touch. Then, I'm retrieving CGPoint from that touch, then passing that point to "indexPathForRowAtPoint" that returns desired indexPath with section and row number. Cool :)

How to add a selected UITableViewController value to a previous UITableViewController?

User clicks on "Remote" button and then the following UITableViewController loads up:
The user then selects any value upon which I call:
[self.navigationController popViewControllerAnimated:YES];
to go back again to the previous UITableViewController (screen shot 1).
How do I add the selected value to the UITableViewController?
I hope I am making sense.
In your remote recipients table view controller, you have the Array with which you are loading the table (say myTestArray). Keep it as a property. And also have a NSInteger property (say selectedRow) which will identify which row user selected. And when you go back to the add recipient table view controller, you can know which row was selected by
[remoteRecipientsController.myTestArray objectAtIndex:remoteRecipientsController.selectedRow];
Or use delegates. Upon row selection the remote recipients will give a call back telling which row was selected.
Update:
If you dont have access to the view controller, use delegates.
You can get both array and the selected row in the delegate method, something as follows:
-(void) remoteRecipient:(RemoteRecipientController *) remoteRecipientController didSelectRow:(NSInteger) row {
// Get the selected row
... = [remoteRecipientController.myTestArray objectAtIndex:row ];
}
Or you can also configure the delegate to just return the selected row (as your string), something as follows:
-(void) remoteRecipient:(RemoteRecipientController *) remoteRecipientController didSelectRow:(NSString *) selectedRecipient {
}
Ofcourse, In this case you need to make remote recipient controller pass the selected row as NSString in the delegate.

UIButton inside UITableViewController

I have a UIButton that is created inside of each table cell. I want to hook up a touch event like so:
[imageButton addTarget:self
action:#selector(startVote:)
forControlEvents:UIControlEventTouchUpInside];
I want to pass data about the current row (the id of the object for that row) to the startVote method. Is there a method that I am missing to do this or am I breaking some best practice. This seems like a very normal thing to do?
I assume you have some sort of NSArray with the data that gets passed on to the buttons in cellForRowAtIndexPath.
Try this in startVote:
- (void)startVote:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDictionary *myData = [myArray objectAtIndex:indexPath.row];
}
EDIT:
If for some reason the row is not selected, you can assign a unique tag to every button upon creation and then:
- (void)startVote:(id)sender {
int myTag = [(UIButton *)sender tag];
NSDictionary *myData = [myArray objectAtIndex:myTag];
}
Maybe you would do some sort of operation with the tag so it can be used as an index (I add a certain amount to every tag so it will not conflict with "automatic" tagging used by the OS.
The UITableViewCell doesn't know, out of the box, what row it's displaying in the table. Remember, the intent is that the same cell instances are re-used all over the table to display its data. That said, your UITableViewController is responsible for setting up the cells and passing them to the system (and has the index path, of course). You could, at that point, do something like:
Assuming it's a custom cell class, set a property on the cell instance to identify what row it's displaying, and which your button can later use.
If you're putting these buttons in the cells as their accessory views, take a look at the table delegate's tableView:accessoryButtonTappedForRowWithIndexPath: method.
If it's a one-section table, you could do something really cheesy like store the row index in the button's tag property. Your startVote: method is passed the button, and could then extract its tag.

iPhone - How to determine in which cell a button was pressed in a custom UITableViewCell

I currently have a UITableView that is populated with a custom UITableViewCell that is in a separate nib. In the cell, there are two buttons that are wired to actions in the custom cell class. When I click one of the buttons, I can call the proper method, but I need to know which row the button was pressed in. The tag property for each button is coming as 0. I don't need to know when the entire cell is selected, just when a particular button is pressed, so I need to know which row it is so I can update the proper object.
Much easier solution is to define your button callback with (id)sender and use that to dig out the table row index. Here's some sample code:
- (IBAction)buttonWasPressed:(id)sender
{
NSIndexPath *indexPath =
[self.myTableView
indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
NSUInteger row = indexPath.row;
// Do something with row index
}
Most likely you used that same row index to create/fill the cell, so it should be trivial to identify what your button should now do. No need to play with tags and try to keep them in order!
Clarification: if you currently use -(IBAction)buttonWasPressed; just redefine it as -(IBAction)buttonWasPressed:(id)sender; The additional callback argument is there, no need to do anything extra to get it. Also remember to reconnect your button to new callback in Interface Builder!
You could use the tag property on the button to specify which row the button was created in, if you're not using tags for anything else.
For a implementation that is not dependent on tags or the view hierarchy do the following
- (void)btnPressed:(id)sender event:(id)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:touchPoint];
}
I have the same scenario. To achieve this, I derived a custom cell. I added two properties, section and row. I also added an owner, which would be my derived TableViewController class. When the cells are being asked for, I set the section/row based on the indexPath, along with the owner.
cell.section = indexPath.section
cell.row = indexPath.row
cell.owner = self
The next thing that I did was when I created the buttons, I associate the button events with the cell rather than with the tableViewController. The event handler can read the section and row entry and send the appropriate message (or event) to the TableViewController. This greatly simplifies house keeping and maintenance by leveraging existing methods and housekeeping and keeping the cell as self contained as possible. Since the system keeps track of cells already, why do it twice!
Even easier:
-(IBAction) buttonPressed {
NSIndexPath *myIndexPath = [(UITableView *)self.superview indexPathForCell: self];
// do whatever you need to do with the information
}
Here's a Swift example...
The UIControl class is the superclass of various iOS widgets, including UIButton, because UIControl provides the target/action mechanism that sends out the event notifications. Therefore a generic way to handle this is as follows:
func actionHandler(control: UIControl)
var indexPath = tableView.indexPathForCell(control.superview!.superview! as UITableViewCell)!
var row = indexPath.row
}
Here's an example of setting up a button control to deliver the action. Alternatively, create an #IBAction and create the action visually with Interface Builder.
button.addTarget(self, action: "actionHandler:", forControlEvents: .TouchUpInside)
You can downcast UIControl parameter to UIButton, UIStepper, etc... as necessary. For example:
var button = control as UIButton
The superview of control is the UITableViewCell's contentView, whose subviews are the UIViews displayed in the cell (UIControl is a subclass of UIView). The superview of the content cell is the UITableViewCell itself. That's why this is a reliable mechanism and the superviews can be traversed with impunity.
You can access the buttons superview to get the UITableViewCell that contains your button, but if you just need the row number, you can use the tag property like the previous post deacribes.
There are multiple methods to fix the problem.
You can use the "tag" property
Give the value indexPath.row as the tag value for the button.
btn.tag = indexPath.row;
Then in the button function, you can easily access the tag value and it will be the index for the clicked button.
-(void)btnClicked:(id)sender
{
int index = [sender tag];
}
You can use the layer property
Add the indexPath as the value in the layer dictionary.
[[btn layer] setValue:indexPath forKey:#"indexPath"];
This indexPath is accessible from the button action function.
-(void)btnClicked:(id)sender
{
NSIndexPath *indexPath = [[sender layer] valueForKey:#"indexPath"];
int index = indexPath.row;
}
With this method you can pass multiple values to the button function just by adding new objects in the dictionary with different keys.
[btnFavroite setAccessibilityValue:[NSString stringWithFormat:#"%d",indexPath.row]];
[btnFavroite setAccessibilityLabel:btnFavroite.titleLabel.text];
[btnFavroite addTarget:self action:#selector(btnFavClick:) forControlEvents:UIControlEventTouchUpInside];
-(void)btnFavClick:(id)sender{
UIButton *btn=(UIButton *)sender;
int index=[btn.accessibilityValue integerValue]]
}
this solution also works in IBAction connected using storyboard cell prototype
- (IBAction)viewMapPostsMarker:(UIButton*)sender{
// button > cellContentView > cellScrollView > cell
UITableViewCell *cell = (UITableViewCell *) sender.superview.superview.superview;
NSIndexPath *index = [self.mapPostsView indexPathForCell:cell];
NSLog(#" cell at index %d",index.row);
}