Get a button inside tableview cell to run the same as didSelectCell - ios

I have a tableview with a UIButton within the cell.
I have created some functionality within didSelectRowAtIndexPath. What I would like is for the same functionality/method to run when the user clicks on the button too.
How can I make the buttonPressed method run the didSelectRowAtIndexPath?
If I cannot do this, I can move the functionality to a new method and have both call this new method. However, how do I get the cell indexPath from the button pressed method?

-(IBAction)playButtonPressed:(id)sender {
NSLog(#"button pressed");
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
UITableView *curTableView = (UITableView *)cell.superview;
NSIndexPath *indexPath = [curTableView indexPathForCell:cell];
[self didSelectRowOrButtonAtIndexPath:indexPath];
}
I made a new method didSelectRowOrButtonAtIndexPath and called this from both the buttonPressed and the didSelectRowAtIndexPath and pass in the indexpath to be used in my method.

Find the UITableViewCell object that contains the button (must be one of its container views, just go up the superview chain).
Find the indexPath with [UITableView indexPathForCell:].

In your cellForRowAtIndexPath, assign indexPath.row to your button's tag (assuming that you only need the row - the idea is to attach the indexPath to the button somehow, tag is just one way to do it).
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
// Init / Reuse the cell ...
cell.button.tag = indexPath.row;
return cell;
}
-(void)buttonPressed:(UIButton*)button {
[self method:button.tag];
}

Related

Custom Cell button Click

My scenario is as follow's:
Custom Cell View
1) I am populating data from server in the custom cell view which is perfectly populated, i want a link store in my array which i want to open in browser, so i want to check which index.row button is clicked so that against that row i can get the url link and open it in browser, so far i have found the solution of button tags but that doesn't work's as well, as if we have two cell's in the screen at same time on click of button both button return's same tag.
2) As the image attached i have another storyboard in which i want to segue to a new view controller, same as mentioned above, i want to pass a specific post title and key as well.
I hope every thing is clear.
Thank's in advance.
To answer the first part of your question. Tags are a pain. It's better to pass along the UIButton as the sender, and, in the action for the button, then you can say something like:
-(void) buttonPresse:(UIButton *)sender
{
CGPoint location = [self.tableView convertPoint:sender.bounds.origin fromView:sender];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
UITableViewCell *cell = [self.table cellForRowAtIndexPath];
//Do what you want with the cell or indexPath
}
I have found the solution of button tags but that doesn't work's as well
Perform following steps to detect which button is selected.
Type the code snippet given below in cellForRowAtIndexPath: method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// DEFINE CELL
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
// SET ACTION METHOD ON CALL BUTTON
UIButton *button = (UIButton *) [self.view viewWithTag:40];
[button setUserInteractionEnabled:YES];
[button addTarget:self action:#selector(checkButtonTapped:) forControlEvents:UIControlEventAllTouchEvents];
}
Add following method for checkButtonTapped:.
- (void)checkButtonTapped:(UIButton *)sender
{
// GET POINT OF THE BUTTON PRESSED
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
// GET INDEXPATH FOR THE CELL WHERE THE BUTTON IS PRESSED
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
if (indexPath != nil)
{
//Use indxPath.row to get item
//Perform operations
}
}
There is another approach if you want to perform action according to the cell selected by the user.
For the case where you want to check which row of the cell is clicked you should use following method.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"ShowindexPath%ld", (long)indexPath.row); }
Here we check for the user interaction on cell. indexPath.row will return index number for the cell selected by user. You can perform other actions in place of NSLog method.
For the purpose to send value while performing segue use following steps:
Create property in the NewViewController.h file where you want to perform segue as follow:
#property (nonatomic) NSString* receivedValue;
#synthesize property by writing following code in NewViewController.m file within #implementation and #end
#synthesize receivedValue;
ImportNewViewController.h file in TableViewController.m file.
Go to prepareForSegue: method in the TableViewController.m file from where you want to send the value and write following code according to your class names within it.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NewViewController *nVC = [segue destinationViewController];
[nVC setReceivedValue:sendValue];
}
Here sendValue is the value that you want to send.
That's all.
Build and run your project and enjoy.
You can extend UITableViewCell and add a touple property to it. key containing the index.row and value containing the URL eg:- 1:"www.stackoverflow.com". When you click on a button, all you have to figure out is the index.row and from that you can get the value that you are looking for.
you can add target for button in cellForRowAtIndexPath like :
[cell.yourButton addTarget:self action:#selector(buttonAction:event:) forControlEvents:UIControlEventTouchUpInside];
here you can receive the action for this button
-(void)buttonAction:(UIButton *)sender event:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPos = [touch locationInView:self.tblview];
NSIndexPath *indexPath = [self.tblview indexPathForRowAtPoint:touchPos];
if(indexPath != nil){
// handle click event..
}
}
surely it will work.........

UIButton tag value doesn't pass in prepareForSegue method in UITableViewController

The feed of my app is managed by a UITableViewController where I set custom cells that are instances of a UITableViewCell sub class.
One property of that sub class is a UIButton called flameRelation:
#property (weak) IBOutlet UIButton* flameRelation;
I am creating a dynamic segue to a detail view controller depending on the class of the sender. If the sender is the cell itself, I pass a given set of data to my detail view controller. If the sender is the flameRelation button, I pass another.
To achieve this, I am looking at the following 2-step approach:
1) Since I need to know the indexpath.row of the cell where the FlameRelation button was pressed, I set the tag of that button in the UITableView method that sets each cell of my feed as follows:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Set a bunch of things before setting UIButton flameRelation tag
[cell.flameRelation setTag:indexPath.row];
And I am printing the tag which allows me to check that the tag is being set when I scroll down my feed after launching my build (I see the numbers incrementing as I scroll down, as expected).
NSLog(#"The button tag for this cell is set to %ld",(long)[cell.flameRelation tag]);
2) In the prepareForSegue method that allows the user to transition to the detail view controller with the relevant information, I test the class of the sender first. If the class of the sender is UIButton, I attempt to pass the right information to the detail view controller by setting the value of the indexpath to the value of the tag:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"FlameDetail"]) {
FlameDetailViewController* flameDetailController = (FlameDetailViewController*) segue.destinationViewController;
if ([sender isKindOfClass:[FlameCellTableViewCell class]])
{
NSIndexPath* indexPath = [self.tableView indexPathForCell:sender];
NSLog(#"The indexPath is: %#", indexPath);
flameDetailController.flame = [self.feed flameAtIndex:indexPath.row];
NSLog(#"class for object sender: %#", NSStringFromClass([sender class]));
}
else if ([sender isKindOfClass:[UIButton class]])
{
NSLog(#"The button tag is set to %ld",(long)[sender tag]);
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
NSLog(#"The indexPath from UIButton is: %#", indexPath);
flameDetailController.flame = [self.feed flameAtIndex:indexPath.row];
NSLog(#"The value of indexPath.row is %ld",(long)indexPath.row);
NSLog(#"class for object sender: %#", NSStringFromClass([sender class]));
flameDetailController.findOutView.hidden = NO;
[flameDetailController.flameAction setTitle:#"CHAT NOW" forState:UIControlStateNormal];
NSLog(#"Yes, the sender is UIButton");
NSLog(#"The title of flameAction is set to %#", flameDetailController.flameAction.titleLabel.text);
}
}
Everything works well if I tap on the cell itself, but if I tap on the flameRelation button, I see in my logs that the getter on tag returns 0. Which obviously doesn't transfer the proper information to my target view controller.
Thanks!
First of all why you are converting your tag value to indexPath and then getting your model data with the row number?
Your code:
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
flameDetailController.flame = [self.feed flameAtIndex:indexPath.row];
Try this instead:
flameDetailController.flame = [self.feed flameAtIndex:sender.tag];
I do not see a reason why this approach would not work. If it does not you need to share more code/details.
However, I would want to suggest another alternate (no so great though):
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];

How do you get the indexPath of the cell you are tapping?

I am trying to execute an IBAction when a long-press is performed on a cell in a UITableView. The action involves the content of the cell so I need to get the indexPath in order to retrieve the content from a dictionary in local storage. The IBAction method is defined in the MasterViewController.m file which contains the UITableView methods and is subclassed from UITableViewController. I have tried all of the following, and they all return null instead of the indexPath for the cell.
UITableViewCell *cell = (UITableViewCell *)self;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
I have also seen a few years-old answers to similar questions that use the position of the cell in the view, but I can't get any of those to work either.
UPDATE:
The IBAction, sendToPB, is being defined in a subclass of UITableViewController. There is a long-press gesture recognizer added to the cell in Interface Builder, with Sent Actions connected to sendToPB. The action is supposed to be copying the content of the cell to the clipboard when you long-press on the cell in the table view. All the ways I have tried so far return null for indexPath.
- (IBAction)sendToPB:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSString *object = self.objects[indexPath.row];
UIPasteboard *pb = [UIPasteboard generalPasteboard];
NSString *pressedCellText = [[Data getAllNotes] objectForKey:object];
[pb setString: pressedCellText];
}
UPDATE:
I have found two problems with this approach. First, the long-press gesture doesn't actually select the row, which is why all of the options that used indexPathForSelectedRow don't work. Second, sender is the gesture recognizer, and not the cell or row, so using sender also produces a null value for indexPath. With these two factors in mind, how else can you detect which cell you performed the long-press on?
You can get indexPath Like This on longPressGesture!
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
CGPoint p = [gestureRecognizer locationInView:self.myTableView];
NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
if (indexPath == nil) {
NSLog(#"long press on table view but not on a row");
}
else if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"long press on table view at row %d", indexPath.row);
}
else
{
NSLog(#"gestureRecognizer.state = %d", gestureRecognizer.state);
}
}
may Be this Link will help you a little more
Declare variable 1st in .h file as
NSIndexPath *hitIndex;
then on long press method u can get the position of cell & hence indexpath
(void)longPressMethod:(UIButton *)btn
{
CGPoint hitPoint = [btn convertPoint:CGPointZero toView:tbl_traits];
hitIndex = [tbl_traits indexPathForRowAtPoint:hitPoint];
}
You can do it using Gesture Recognizers. Hope these snippets help.......
In your .h file
#interface yourClass ()
{
UILongPressGestureRecognizer *longPressRecognizer;
}
In viewDidLoad,
longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressDetected:)];
longPressRecognizer.minimumPressDuration = 2;
longPressRecognizer.numberOfTouchesRequired = 1;
longPressRecognizer.delegate = self;
In cellForRowAtIndexPath, just before return statement
[cell addGestureRecognizer:longPressRecognizer];
And at the end,
- (void) longPressDetected:(UILongPressGestureRecognizer *)recognizer
{
UITableViewCell *selectedCell = (UITableViewCell *)recognizer.view;
// Your required code here
}
Edit: Thanks to #RegularExpression
First be sure to set the delegate of your tableView
self.myTableView.delegate = self
I believe this is what you are looking for:
Swift
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//save the indexPath.row as an integer inside a property or pass it to your action
}
You can then save the index of from the above method or simple call your action passing that index inside the above method.
Objective-C
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//save the indexPath.row as an integer inside a property or pass it to your action
}
If this is inside a UITableViewController subclass, then casting self (which is an instance of the UITableViewController subclass) to UITableViewCell will not return the cell selected.
There is really 2 ways of doing this:
1- The easy way: Don't use an IBAction and just implement the delegate methods:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
2- The relatively easy way: in your IBaction, you can get the selected cell by using the property:
self.tableview.indexPathForSelectedRow
This property will give you the indexpath of the selected cell.
If you attached the UILongPressGestureRecognizer to the cell by calling cell.addGestureRegognizer(_: _: _:) you should retrieve the cell from the sender by doing
let touchedView = sender.view as! UITableViewCell
Anyway, the best way to achieve this usually is by inspecting the dataSource instead of calling the UITableViewDataSource methods
You could subclass UITableViewCell and add an IVar for the index path and set that when cellForRowAtIndexPath is called for the UITableView dataSource protocol.

Button inside tableViewCell not calling IBAction

I have created both UICollectionView and UITableView on my View
Inside tableViewCell's ViewController, there is an action listener :
.h:
- (IBAction)addItem:(id)sender
.m:
- (IBAction)addItem:(id)sender {
UIButton * button = ( UIButton * )sender;
NSLog(#"add item button clicked");
}
I wanted to execute this function by clicking both the Cell in my UICollectionView and a UIButton inside each tableViewCell
the following codes work perfectly for clicking my UICollectionView's cell
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
Item * selectedItem = [collectionDataArray objectAtIndex:indexPath.row];
//get item object from my collectionView's data array
if ([tableDataArray containsObject:selectedItem]){
//check if my tableView's data array having the same object
NSUInteger itemIndex = [tableDataArray indexOfObject:selectedItem];
NSIndexPath * indexpathOfTable = [NSIndexPath indexPathForRow:itemIndex inSection:0];
//get indexPath of the cell containing the item object
myTableCell * tableCell = (myTableCell*)[myTableView cellForRowAtIndexPath:indexpathOfTable];
[myTableCell addItem:self];
//executing action listener here
}else{
[tableDataArray addObject: selectedItem];
}
[myTableView reloadData];
}
didSelectRowAtIndexPath is working fine as well
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"cell clicked");
}
However, it will no longer execute the addItem function for the UIButton I added inside my UITableView no matter I add selector for the button when generating tableViewCell or I create UIButton with linked IBAction for my tableViewCell inside Interface Builder
I've implemented both UITableViewDelegateand UICollectionViewDelegate
I think it never detect my clicking gesture for my UITableView but detect the one for UICollectionView
Is there anyone help me on this? thanks a lot

Use a button on a UICollectionViewCell to display data from an array

I have an array of NSStrings, one UILabel & a UICollectionView.
My Question:
I want the array's count to determine how many UICollectionViewCell's there are.
Each UICollectionViewCell contains a button. Upon click, I want this button to cause the data in the array that corresponds to the UICollectionViewCell's number to be displayed in the label.
For example, if the user clicks on the 13th UICollectionViewCell's button, then the 13th NSString in the array would become the UILabel's text.
What I have done:
I have made my own subclass of UICollectionViewCell for the nib file that I use for all of the UICollectionViewCells, & connected the button to the .h file as a IBAction. I have also imported the MainViewController.h, which is the one that contains the array property that stores the NSStrings.
When I edit the code in the UICollectionViewCell's action, I cannot access the array property. The button does work - I placed an NSLog in the IBAction's method, which does work.
I have searched through tens of other answers on SO, but none answer my specific question. I can update this with samples of my code if requested.
I have made my own subclass of UICollectionViewCell for the nib file
that I use for all of the UICollectionViewCells, and connected the
button to the .h file as a IBAction.
If you connect the IBAction to the subclass of collectionViewCell you would need to create a delegate to make the touch event available in the viewController where you are displaying the data.
One easy tweak is to add the button the collectionViewCell, connect it's IBOutlet to the cell. But not IBAction. In the cellForRowAtIndexPath: add an eventHandler for button in that viewController containing collectionView.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//Dequeue your cell
[cell.button addTarget:self
action:#selector(collectionViewCellButtonPressed:)
forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (IBAction)collectionViewCellButtonPressed:(UIButton *)button{
//Acccess the cell
UICollectionViewCell *cell = button.superView.superView;
NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
NSString *title = self.strings[indexPath.row];
self.someLabel.text = title;
}
Please try like this..
In YourCollectionViewCell.h
Create an IBOutlet not IBAction called button for the UIButton that you added to the xib. Remember you should connect the outlet to the cell object not to the file owner in the xib.
MainViewController.m
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
cell.button.tag = indexPath.row;
[cell.button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
-(void)buttonPressed:(UIButton*)sender
{
NSLog(#"%d : %#",sender.tag,[array objectAtIndex:sender.tag]);
self.textLabel.text = [array objectAtIndex:sender.tag];
}
Edit- Handle multiple sections
-(void)buttonPressed:(UIButton*)sender
{
NSIndexPath *indexPath = [self.collectionView indexPathForCell: (UICollectionViewCell *)sender.superview.superview];
NSLog(#"Section : %d Row: %d",indexPath.section,indexPath.row);
if (0 == indexPath.section) {
self.textLabel.text = [firstArray objectAtIndex:indexPath.row];
}
else if(1 == indexPath.section)
{
self.textLabel.text = [secondArray objectAtIndex:indexPath.row];
}
}
When I edit the code in the UICollectionViewCell's action, I cannot access the array property.
That's because you connected the button action to the "wrong" object. It needs to be connected to the MainViewController (or whoever it is that does have access to the array property).
You are going to have several tasks to perform:
Receive the button action message.
Access the array (the model for the data).
Throw a switch saying which cell should now have its label showing.
Tell the collection view to reloadData, thus refreshing the cells.
All those tasks should most conveniently belong to one object. I am presuming that this is MainViewController (and thus I am presuming that MainViewController is the delegate/datasource of the collection view).

Resources