I have a UITableView with custom cell TaskCell. TaskCell has checkboxImageView and I want that when user clicks on the checkboxImageView a method is fired. For some reason it is always firing the didSelectTableView delegate method. Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TaskCell";
Task *task = [tasks objectAtIndex:[indexPath row]];
TaskCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[TaskCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell bindTo:task];
return cell;
}
TaskCell.m:
-(void) prepareGestureRecognizers
{
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onSingleTap:)];
singleTapGestureRecognizer.delegate = self;
singleTapGestureRecognizer.numberOfTapsRequired = 1;
self.checkboxImageView.userInteractionEnabled = YES;
[self.checkboxImageView addGestureRecognizer:singleTapGestureRecognizer];
}
-(void) onSingleTap:(UITapGestureRecognizer *) sender
{
NSLog(#"single tap!");
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void) bindTo:(Task *)task
{
[self prepareGestureRecognizers];
self.titleLabel.text = task.title;
}
If you add the gesture recognizer in your TaskCell.m, then the following line
singleTapGestureRecognizer.delegate = self;
sets the delegate of the recognizer to the cell, not your controller. You should add the recognizer in your controller file so that the delegate is properly set up.
I'm not sure if this will work as I haven't tried myself, but you can try set the recognizer up in your Storyboard and let it be a #property of your cell. Then you can set the delegate to be your controller in your controller file.
Related
I found already some solution how to detect touch in my cell, but they are made for one section. I have more then 1(8 tbh). Following code are making touch for few cells instead of one. So question is, what the clear solution to my problem? Here the code:
- (CatalogItemTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CatalogItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
CatalogItemModel *currentItemModel;
if(isCatSelected) {
currentItemModel = [[self.itemsArray objectForKey:[[self.sectionArray objectAtIndex:selectedIndexPath] valueForKey:#"id"]] objectAtIndex:indexPath.row];
} else {
currentItemModel = [[self.itemsArray objectForKey:[[self.sectionArray objectAtIndex:indexPath.section] valueForKey:#"id"]] objectAtIndex:indexPath.row];
}
[cell setItemModel:currentItemModel];
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(didTapFav:)];
[cell.overFavorite addGestureRecognizer:gestureRecognizer]; //overFavorite is UIView to detect touch
return cell;
}
Action func:
-(void)didTapFav:(UITapGestureRecognizer*)recognizer {
NSString *token = [ProfileManager getToken];
if(token.length > 0){
[[NSNotificationCenter defaultCenter] postNotificationName:#"addToFavorite" object:self];
} else {
[self showErrorWithTitle:#"Auth" andText:#"To add item in Favorite!"];
}
}
Function inside CatalogItemTableViewCell:
-(void)addToFavorite {
if(isFavorite) {
[ApiManager tryAddToFavItem:[NSString stringWithFormat:#"%ld", (long)self.currentModel.uid] :^{
//Some API request
}];
}
}
First of all add gestureRecognizer for your CollectionView
UIGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tap:)];
tapGesture.delegate = self;
[self.collectionView addGestureRecognizer:tapGesture];
then get the IndexPath or Cell you want to access in - (void)tap:(UITapGestureRecognizer* )sender;
if (sender.state == UIGestureRecognizerStateEnded) {
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[sender locationInView:self.collectionView]];
}
I have a custom cell with various IBOutlets, but on one button I want to add a UILongPressGestureRecognizer for long press gestures. Here is my code (btw outlets are connected correctly and the IBAction method of the button is called correctly):
MyCustomCell.h
#interface MyCustomCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIButton *myButton;
#property (strong, nonatomic) UILongPressGestureRecognizer *longPressGestureRecognizer;
#end
MyCustomCell.m
- (void)awakeFromNib
{
// Initialization code
self.longPressGestureRecognizer = nil;
}
MyViewController.m
#import MyCustomCell.h
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"MyCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
if (!cell){
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPressGestures:)];
cell.longPressGestureRecognizer.minimumPressDuration = 1.0f;
cell.longPressGestureRecognizer.allowableMovement = 300.0f;
[cell.myButton addGestureRecognizer:cell.longPressGestureRecognizer];
}
- (void)handleLongPressGestures:(UIGestureRecognizer *)recognizer
{
if ([recognizer.view isKindOfClass:[UIButton class]]){
if (recognizer.state == UIGestureRecognizerStateBegan){
NSLog(#"Long press began");
} else if (recognizer.state = UIGestureRecognizerStateEnded){
NSLog(#"Long press ended");
}
}
}
The problem is handleLongPressGestures: method is never called.
the longPressGestureRecognizer should be a property on the controller and not the view(MyCustomCell). Move the property over to MyViewController and try again. My guess is something weird is happening when it queues and dequeues the MyCustomCell.
Objects(cells) for reuse should be lightweight. In this case, the longPressGestureRecognizer's target is the view controller and is nasty.
Try out this way
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"MyCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
if (!cell){
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
if ([[cell gestureRecognizers] count]<1) {
UILongPressGestureRecognizer *longPressGestureRecognizer;
longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPressGestures:)];
longPressGestureRecognizer.minimumPressDuration = 1.0f;
longPressGestureRecognizer.allowableMovement = 300.0f;
longPressGestureRecognizer.delegate = self;
[cell.myButton addGestureRecognizer:cell.longPressGestureRecognizer];
}
}
This type of code works for me.
Try This!
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UILongPressGestureRecognizer *LongPress=[[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPressGestures:)];
LongPress.minimumPressDuration = 1.0f;
LongPress.allowableMovement = 300.0f;
[cell.myButton addGestureRecognizer:LongPress];
}
- (void)handleLongPressGestures:(UIGestureRecognizer *)recognizer
{
if ([recognizer.view isKindOfClass:[UIButton class]]){
if (recognizer.state == UIGestureRecognizerStateBegan){
NSLog(#"Long press began");
}
else if (recognizer.state = UIGestureRecognizerStateEnded)
{
NSLog(#"Long press ended");
}
}
}
My apps MainViewController uses a UITableView with custom UITableViewCells from CustomCell. With UIPanGestureRecognizer the user can slide a cell left or right. After the slide, the textLabel.text and slide direction are stored to static NSStrings.
The animation code is CustomCell and works fine.
How could MainViewController know or be notified when CustomCell's recognizer.state == UIGestureRecognizerStateEnded?
CustomCell
static NSString *cellAction = NULL; // textLabel.text
static NSString *slideTo = NULL; // slide direction
-(id)initWithStyle{
UIGestureRecognizer* recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self addGestureRecognizer:recognizer];
}
-(void)handlePan:(UIPanGestureRecognizer *)recognizer{
}
MainViewController
-(void)viewDidLoad{
actionTable = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
[self.view addSubview:middleActionTable];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:ident forIndexPath:indexPath];
return cell;
}
After this works I plan on using the 2 static strings from CustomCell to perform a modal segue from MainViewController to AnotherViewController. I only need the 2 strings after the slide action.
add this code
UIGestureRecognizer* recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self addGestureRecognizer:recognizer];
right after you create the cell in your MainViewController like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:ident forIndexPath:indexPath];
//more of your existing code here
UIGestureRecognizer* recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self addGestureRecognizer:recognizer];
return cell;
}
And move your handlePan: method to the MainViewController.
Unless there's a strong reason for you to have the handlePan: method in the cell class, its best to add have it in the MainViewController (if you want to avoid creating/setting a delegate or using blocks)
I'm having a problem in getting a value in uitableviewcell.
first of all, i have a label on my cell which I've created a tap gesture on it. What i want to do is on tapping that label, viewUser method will be call and it will get the details of that cell being tapped.
Here is my code:
on cellForRowAtIndexPath:
cell.userNameLabel.text = [[_workflowList objectAtIndex:indexPath.row] userName];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewUser:)];
tapGestureRecognizer.numberOfTapsRequired = 1;
[cell.userNameLabel addGestureRecognizer:tapGestureRecognizer];
cell.userNameLabel.userInteractionEnabled = YES;
Now, when i call my ontap method which is viewUser:
- (IBAction)viewUser:(id)sender {
//this should not be hard coded
//data should come from cell.
//usernamelabel or i will get the index selected
//and get the details in my array
// like this --> [_workflowList objectAtIndex:index]
WorkflowProfileViewController *chkDtl = [[WorkflowProfileViewController alloc]init];
chkDtl.name = #"USER, USER USER"; ;
chkDtl.phoneNo = #"09173210836";
chkDtl.email = #"romelync#sxchange.com";
[self.navigationController pushViewController:chkDtl animated:YES];
}
Please help me on this.
The best option would be to use UITableView delegate method tableView:didSelectRowAtIndexpath: as below:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WorkflowProfileViewController *chkDtl = [[WorkflowProfileViewController alloc]init];
chkDtl.name=[[_workflowList objectAtIndex:indexPath.row] userName];
[self.navigationController pushViewController:chkDtl animated:YES];
}
Don't forget to set delegate of your tableView.
UPDATE: Then I think you want to do something like below. In your cellForRowAtaIndexPath: add following:
cell.userNameLabel.tag=indexPath.row;
And in viewUser method:
UITapGestureRecognizer *tap=(UITapGestureRecognizer*)sender;
WorkflowProfileViewController *chkDtl = [[WorkflowProfileViewController alloc]init];
chkDtl.name=[[_workflowList objectAtIndex:tap.view.tag] userName];
[self.navigationController pushViewController:chkDtl animated:YES];
When creating UILable you could put the tag value as row number
lable.tag = indexPath.row
In your method then retrieve label and look for tag value.
Something like below will get the cell you are tapping (replace swipe with tap):
- (void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer{
CGPoint location = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *swipedIndexPath = [self.tableView indexPathForRowAtPoint:location];
self.currentSwipedCell = [self.tableView cellForRowAtIndexPath:swipedIndexPath];
}
Havent tested it yet but:
-(void)viewUser:(UITapGestureRecognizer):gestureRecognizer{
CGPoint location = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
self.currentTappedCell = [self.tableView cellForRowAtIndexPath:indexPath];
NSLog(self.currentTappedCell.name); // If you have a custom cell with a name property
}
Definitely you should use the proper delegate methods instead implementing UITapGestureRecognizer on an UITableViewCell. Then you can get the informations you want pretty easily:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *theUserNameYouWantToGet = [_workflowList objectAtIndex:[indexPath row]];
}
EDIT:
If you want that action not to work for the whole cell, you could subclass UITableViewCell, add properties to it and implement your own delegate protocol to that cell:
#protocol JWTableViewCellDelegate;
#interface JWTableViewCell : UITableViewCell
#property (nonatomic, retain) NSString *username;
#property (nonatomic, assign) id<JWTableViewCellDelegate>delegate;
#end
#protocol JWTableViewCell <NSObject>
- (void)tableViewCellDidClickUsername:(JWTableViewCell *)cell;
#end
#implementation JWTableViewCell
- (void)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self setupView];
}
return self;
}
// if you use a prototyping NIB
- (void)awakeFromNib {
[self setupView];
}
- (void)setupView {
// add gesture recognizer
}
- (void)handleGesture {
if ([_delegate respondsToSelector:#selector(tableViewCellDidClickUsername:)]) {
[_delegate tableViewCellDidClickUsername:self];
}
}
Then use this in your viewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
JWTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"reuseID" forIndexPath:indexpath];
[cell setUsername:#"Paul"];
[cell setDelegate:self];
}
- (void)tableViewCellDidClickUsername:(JWTableViewCell *)cell {
NSString *theUserNameYouWantToGet = [cell username];
}
I currently have a custom UITableViewCell which contains a UIImageView and trying to add a UITapGestureRecognizer on the UIImageView with no luck. here is snippet of the code.
//within cellForRowAtIndexPath (where customer table cell with imageview is created and reused)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleImageTap:)];
tap.cancelsTouchesInView = YES;
tap.numberOfTapsRequired = 1;
tap.delegate = self;
[imageView addGestureRecognizer:tap];
[tap release];
// handle method
- (void) handleImageTap:(UIGestureRecognizer *)gestureRecognizer {
RKLogDebug(#"imaged tab");
}
I've also set userInteractionEnabled on the cell and the superview of the UIImageView but still no luck, any hints?
EDIT:
I've also remove cell's selection by cell.selectionStyle = UITableViewCellSelectionStyleNone; Could this be a problem
UIImageView's user interaction is disabled by default. You have to enable it explicitly to make it respond to touches.
imageView.userInteractionEnabled = YES;
Swift 3
This worked for me:
self.isUserInteractionEnabled = true
In my case it looks like :
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = CELL_ROUTE_IDENTIFIER;
RouteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[RouteTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
}
if ([self.routes count] > 0) {
Route *route = [self.routes objectAtIndex:indexPath.row];
UITapGestureRecognizer *singleTapOwner = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(imageOwnerTapped:)];
singleTapOwner.numberOfTapsRequired = 1;
singleTapOwner.cancelsTouchesInView = YES;
[cell.ownerImageView setUserInteractionEnabled:YES];
[cell.ownerImageView addGestureRecognizer:singleTapOwner];
} else {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
And selector :
- (void)imageOwnerTapped:(UISwipeGestureRecognizer *)gesture {
CGPoint location = [gesture locationInView:self.tableView];
NSIndexPath *tapedIndexPath = [self.tableView indexPathForRowAtPoint:location];
UITableViewCell *tapedCell = [self.tableView cellForRowAtIndexPath:tapedIndexPath];
NSIndexPath *indexPath = [self.tableView indexPathForCell:tapedCell];
NSUInteger index = [indexPath row];
Route *route = [self.routes objectAtIndex:index];
}