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.
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)
So i have a custom UITableViewCell which contains three UILabel. The UITableViewCell is such that the UILabel completely cover the cell.
Now i want to detect whenever user taps on the cell. Problem is as the UILabel cover the cell I cannot use UITableView delegate method for detecting touch on the cell.
I thoughout about using gesture recoginzers on the UILabel but then i don't get the index of the touched cell. I also thought about placing a transparent button on top of the cells but here there is also the same problem that i can't get the index of the touched cell.
Can anybody guide me with an approach on how can i accomplish detecting taps with tableView didSelectRowAtIndexPath when UILabel are covering the cell.
Try to set userInteractionEnabled to false in all labels in cell. This will pass touch to the cell and then you can use UITableView delegates. Be sure that cell stays userInteractionEnabled = YES
To get the touch event besides didSelect method try this. In your custom cell class add a block like,
typedef void(^TappedCell)(CustomCell *cell);
and add a property for it,
#property (nonatomic, strong) TappedCell tappedCell;
and on transparent button action
- (IBAction)buttonTapped {
if (self.tappedCell) {
self.tappedCell(self);
}
}
And in cellForRow method
__weak type(self)weakSelf = self;
cell.tappedCell = ^ (CustomCell *tappedCell) {
//Ur actions goes here
//for getting index
NSIndexPath *indexPath = [weakSelf.tableView indexPathForCell:tappedCell];
[weakSelf someActionWithIndexPath:indexPath];
};
It doesnt matter whether UILabel hide your cell or UIImageView hide it. It will automatically detects tableView didSelectRowAtIndexPath. Check it first you wont face any problems. Did you try to implement tableview in detail first
I have a a custom UITableViewCell class and in it I have a UIImageView. This UIImageView is only displayed when the text of the UITableViewCell is equal to a certain string, eg "Home". When the method mapView:regionWillChangeAnimated: is called, I want to apply an animation on this UIImageView.
My question is how can I, when mapView:regionWillChangeAnimated: is called, go through my UITableView and custom UITableViewCells and perform an animation on the UIImageView within the cells which have the UIImageView set as visible?
I've been able to call methods on cells before using the UITableView delegate methods but I'm struggling to find a solution in this scenario because the the UITableView is not being directly called by the map panning method, it's not a didSelectRowAtIndex path issue?
Thank you.
If you have reference to table view in your map delegate method, you can get all visible cells using visibleCells method in UITableView and apply animation for them if needed. General structure may look like:
// Controller
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
...
[self applyCellsAnimation];
}
- (void)applyCellsAnimation {
for (CustomCell* cell in [self.tableView visibleCells]) {
[cell performImageAnimationIfNeeded];
}
}
// CustomCell
- (void)performImageAnimationIfNeeded {
if (!self.myImageView.hidden) {
// perform animation
}
}
You can get an array of all the visible rows in your table view using
[myTableView visibleCells]
You then just need to integrate through each cell and animate the image.
i.e.
for (MyCustomCell* cell in [myTableView visibleCells])
{
[cell animateImage];
}
The implementation of animateImage can then do whatever you want - just check the imageView.hidden property and animate it if the imageView is visible.
I have the tag for a custom UITableViewCell but I am not sure how I should reference it?
What is the standard approach here.
I thought something close to this but of course this will not work right?:
CustomCell *cell = (CustomCell*)[self.mainTableView cellForRowAtIndexPath:[NSIndexPath indexPathForItem:tag inSection:0]];
I make this reference when a button is pressed in the custom implementation of that cell using a delegate method to pass it to my view controller.
You should not refer to cell itself, because is just interface to show your data. Cells can be (and should be) reused and filled with different data.
Better is store data id, or at lest index of element that cell.
Read more in docs A Closer Look at Table View Cells
To get from a button in a cell to the cell itself, walk up the view hierarchy:
UIView* v = sender; // sender is the button that was tapped
do {
v = v.superview;
} while (![v isKindOfClass: [UITableViewCell class]]);
DiscoverCell* cell = (DiscoverCell*)v;
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.