I have a custom UITableViewCell that I defined in a storyboard. I added a gesture to an image within the table cell. I capture the gesture just fine and change the image.
What I need to do now is remove the tableCell from the table list, but I'm having trouble finding a reference to that table cell.
How do I get the table cell indexPath or a reference to that table cell? I don't really want to climb the superview later as it seems to me there must be an easier/better way.
Thanks.
I actually found a solution. Using target action I did this.
-(void)checkMarkTapDetected:(id)sender {
// Update the image
UIImageView *checkMarkImage = (UIImageView *)[sender view];
checkMarkImage.image = [UIImage imageNamed:#"checkbox_checked.png"];
// Get recognizer and the place it fired in the tableview
UIGestureRecognizer *gestureRecognizer = [[checkMarkImage gestureRecognizers] lastObject];
CGPoint location = [gestureRecognizer locationInView:self.tableView];
// Get table cell index based on gesture location in table view cell
_checkMarkRowIndexPath = [self.tableView indexPathForRowAtPoint:location];
}
I see two options. You can use deleteRowsAtIndexPaths:withRowAnimation: or you can send reloadData to your tableView. reloadData will cause your delegate method cellforRowAtIndexPath (and related methods) to be called again but this time you will not create that very cell. Your numberOfRowsInSection will have to reflect the decrease of rows too.
Related
I'm developing an iOS app with a UITableView that requires a swipe gesture to perform a certain action for any cell (row) in the table.
When I initially implemented the IBAction for the gesture in my view controller (the one with the UITableView in it), I wasn't even able to run the app, as Xcode informed me with an error that it doesn't allow attaching gestures to repeating interface elements (the cell being a repeating element, since a new one is generated each time one is needed via dequeueing a reusable cell).
So I then proceeded to place the IBAction for the swipe gesture inside my custom table cell class instead, at which point I no longer receive the error that prevents me from building/running, but am still receiving a warning in the debug console while running the app, which states that since iOS9, the system now enforces the prohibition of gestures attached to repeating elements (in this case, my table cell).
If anyone has insight into gesture recognizers, I'd appreciate it if you could help me figure out the following questions.
Should I take this warning at face value and assume that I'm not allowed to attach any gestures to table cells at all?
In either case, is there some other way to attach a gesture to repeating elements like prototype table cells and avoid any kind of warnings/prohibitions?
You should put the swipe in your viewcontroller and get a cell through Swipe IBAction with the code below. Once you've done that, you can do what you want: cell.do_something or cell.element.do_something
You get the cell with the position of swipe, like:
Objective C:
CGPoint location = [sender locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
Swift:
let location : CGPoint = sender.locationInView(self.tableView)
let indexPath : NSIndexPath = tableView.indexPathForRowAtPoint(location)
let cell : UITableViewCell = tableView(tableView, cellForRowAtIndexPath: indexPath)
I have a UITableViewCell which contains a UICollectionView. The UITableViewCell also contains a UIPageControl. I want to change the dots as the UICollectionView is swiped. I am using
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
to get the current visible UICollectionViewCell. But my problem is that since the UICollectionView lies in UITableViewCell to fetch the reference to the collectionView I require the indexPAth of the current table view in which collection cell is being swiped. How can I do this?
I want to do this:
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
// Change the dots
CustomTableCell *tableCell = [self.currentTable cellForRowAtIndexPath:_tablecellIndex];
NSInteger currentIndex = tableCell.currentCollectionView.contentOffset.x / tableCell.currentCollectionView.frame.size.width;
tableCell.currentPageControl.currentPage = currentIndex;
}
But how do I get the _tablecellIndex?
I tried doing :
NSArray *indexes = [self.currentTable visibleCells];
_tablecellIndex = indexes[0];
But this is not always true as sometimes the table cells are displayed half and user is swiping second cell.
You need to ask the tableview itself, what indexpath a given cell has. You do that with this command :
[self.formTableView indexPathForCell:myCell];
The other problem in your case is that you are within the collection view on the cell, and not within the tableview itself. So theres a few ways to do that - one nice way is to set up a delegate on the cell that can access the tableview. Thats a bit involved, so heres an even simpler way (self in this case is the cell object):
UITableView *parentTableView = (UITableView*)self.superview;
NSIndexPath *cellIndexPath = [parentTableView indexPathForCell:self];
That should do the job.
I need to change the value inside a UITableViewCell when the user taps on it.
I need to modify the value trough an animation of a value inside a UITableViewCell.
Right now, I've implemented a UITapGestureRecognizer when the user taps on the UILabel, like so:
UITapGestureRecognizer *tapOnAmount = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnBalance)];
[cell.amountLabel setUserInteractionEnabled:YES];
[cell.amountLabel addGestureRecognizer:tapOnAmount];
Changing the values in a method didTapOnBalance will crash the app, like so:
-(void)tapOnBalance{
NSString *headerIdentifier = #"HeaderCell";
HeaderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:headerIdentifier];
cell.amountLabel.text = #"new Value"; // this will crash because at runtime
// the compiler won't recognize cell.amountLabel...
}
Implementing this in the UITableViewCell will cause me to send the values of the HeaderTableViewCell to the subclass and I don't know how to do that either.
You can't just deque a new cell, that will not give you the cell that the user tapped - it will make a new one. But, if you change your tap handler just a little, you can get the index path of the cell tapped from the gesture.
You need a slight change to the initialization of the gesture (look at the selector):
UITapGestureRecognizer *tapOnAmount = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnBalance:)];
[cell.amountLabel setUserInteractionEnabled:YES];
[cell.amountLabel addGestureRecognizer:tapOnAmount];
and then another slight change to your handler:
- (void)tapOnBalance:(UITapGestureRecognizer *)sender
{
CGPoint location = [sender locationInView:self.view];
CGPoint locationInTableview = [self.tableView convertPoint:location fromView:self.view];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:locationInTableview];
// then you can either use the index path to call something like configureCell or send a didSelectRowAtIndexPath like this:
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}
Your code is totally wrong.
You're creating a new cell when the user taps on an existing cell, and trying to change the value displayed in that new cell. Don't do that.
Instead, change the data in your table view's data model, then tell your table view to reload that cell (as explained in ZAZ's answer.) If you've changed the data model to reflect new info for your cell, reloading it will cause it to be displayed with the new settings.
you must implement didSelecRowAtIndexPath and write in it the following line of code after the changing the value to animate the tapped row
[self.myTableView reloadRowsAtIndexPaths:indexPath] withRowAnimation:UITableViewRowAnimationNone];
Hope it helps!
I'm trying to implement the block method outlined in the answer to the question in this link, but I don't understand how to set the block. Assuming that...
cell.onButtonTapped = ^{
[self buttonSelectedAtIndexPath:indexPath];
}
is pseudo code, how would I actually implement this assuming I have a UITableViewCell (not a custom cell) and a UIButton within that cell. Is it possible to do this without creating my own UITableViewCell subclass?
If you're gonna do it this way, you'd really have to make a UITableViewCell subclass which is a target of its button, has a property for the block and calls the block when the button is tapped.
There's actually a simple way to know from which indexPath a subview (eg. the button here) of a cell is from. First you'll need a point on the tableView's coordinates, which is contained by the subview. Let's say you'll choose the center of the subview. To convert it to the tableView's coordinates:
CGPoint subViewCenter = [self.tableView convertPoint:subview.center fromView:subView.superView]; // because a view's center is on its superview's coordinates
to get the indexPath:
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:subViewCenter];
No, as per the answer you are referring to, you need a custom UITableViewCell. Essentially you are calling a method on the cell and passing the current indexPath for that cell.
Whether you use the block method or the delegate method you will need a custom UITableViewCell as you need somewhere to store the indexPath and a method to set it.
I have in one ViewControl two TableViews implemented. Initially one has data and another doesn't.
So, I was wondering how would I implement the gesture event of touching one row in the fulfilled TableView and swipe it to the empty TableView, in order to move that datum.
add the swipe gesture to each cell of your table, this gesture call a Custom method where you pass the indexPath of the cell then in your Custom method write a code for add this object from the array of first table to the second and remove it from first array. Finally you refresh boh table with reloadData method
What I've done so far... (It's slightly different of what #Mirko told)
Added the UISwipeGesture to the table (inside ViewDidLoad method), and defined it to capture the "Swipe Up" event, calling my event handler.
swipeCell = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeUpEvent:)];
swipeCell.direction = UISwipeGestureRecognizerDirectionUp;
[self.tableA addGestureRecognizer:swipeCell];
Implemented the event handler, that get the cell selected by the swipe movement when it starts.
-(IBAction)swipeUpEvent:(UIGestureRecognizer *) sender
{
CGPoint location = [sender locationInView:self.tableA];
NSIndexPath *swipedIndexPath = [self.tableA indexPathForRowAtPoint:location];
NSString *temp = [arrayA objectAtIndex:swipedIndexPath.row];
[arrayB addObject:temp];
[arrayA removeObjectAtIndex:swipedIndexPath.row];
[self.tableB reloadData];
[self.tableA reloadData];
}
It may not be the most elegant solution for the problem, but at least I avoided creating an ActionListener for each cell. I hope it saves me some memory.