Detecting taps on Custom Cells of UITableView - ios

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

Related

Call a method on UIImageView inside of a UITableViewCell

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.

Custom UITableViewCell with Sliders

I have a UITableViewController implementing custom cells via
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
and in the CustomTableViewCell.h file I declared
#property (nonatomic, weak) IBOutlet UISlider *slider;
which is connected to my slider in my storyboard and an IBAction that changes the background of the cell when the slider is adjusted (value changed). My problem is that when I slide down the table view, as soon as my cell is dequeued it is reused with the slider in the same position, and therefore the background an adjusted color. I don't want to keep the entire table in memory, but I need to keep the information input into a cell available for future use. Is there a standard way to handle a problem like this? Thanks.
You can put your slider values into an array, and the dequeueReusableCellWithIdentifier method, you can set the cell slider value from the array
Yes you need to store data for the table in memory (for example slider values in NSArray) and in your UITableView datasource method you need to update state of reused cell. UITableView is smart enough not to load cells for whole table, it loads only visible cells. It is the standard way to do it.
why not configure the cell after method dequeueReusableCellWithIdentifier
cell.backgroundColor = //adjust the color
cell.slider.value = //adjust value

NSIndexPath for UIButton in UITableViewCell

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.

Modify outlet inside UITableView custom cell

I have a custom UITableViewCell that has 2 UITextFields and a UIButton. The text fields are set in the cell:ForRow:AtIndexPath: method. What I need is to change the opacity of this UIButton dynamically, without having to reload the entire tableview. I was thinking of something like cellForRowAtIndexPath:, but how to access the outlet in this cell?
Thanks
When you create the cell in cellForRowAtIndexPath: just maintain a pointer to it in code. If that button is on every cell then you can just create an array of buttons so that you can easily access the button for the cell you want.
UIButton *cellButton = [[UIButton alloc] init];
[allCellButtons addObject:cellButton];

Changing the contentView when an Accessory button is tapped

I've subclassed UITableViewCell to display a UIImage and two UILabel subviews. In the view controller for the table view, in the method cellForRowAtIndexPath: I've enabled an accessory view via setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton.
Cells display correctly.
When I tap on the accessory disclosure button I want to replace the two label subviews with two different label subviews. My approach was the following:
In the subclassed UITableViewCell, inside layoutSubviews, create the
CGRects for the "alternate" labels, position them in the same
places as the two "original" label and hide them via setAlpha:;
When the disclosure button is tapped swap out the set of two
label by adjusting their respective alphas.
The problem is I can't figure out what logic in layoutSubviews I'd use to know whether the accessory button has been tapped. I see that in the view controller accessoryButtonTappedForRowWithIndexPath: is called when that button is tapped and from there it seems like I would call layoutSubviews but can't figure out how to use that fact to accomplish what I'm trying to do.
Am I going about this all wrong? Instead of hiding/showing CGRects with alpha should I simply be creating another subclass of UITableViewCell?
When I tap on the accessory disclosure button I want to replace the two UILabel subviews with two different UILabel subviews.
I'll do the following. Create a public method in your UITableViewCell subclass like the following:
- (void)changeContentForCell;
In this method you could set the contentView as you prefer.
Then in your view controller implement
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cCell = (CustomCell*)[tableView cellForRowAtIndexPath:indexPath];
[cCell changeContentForCell];
}
This is a simple example for change the content. In my opinion you don't have to use layoutSubviews to add views.
Leave this logic in changeContentForCell and then call setNeedsLayout to change your layout. Maybe you could have a variable that tracks the state for your cell: normal state or modified state.
Hope it helps.

Resources