In an iOS App, I have a UITableView (NOT part of a UITableViewController) on which I want to detect long press on custom UITableViewCells with the following method:
- (void)viewDidLoad
{
myTableView.delegate=self;
myTableView.dataSource=self;
UILongPressGestureRecognizer *longTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTapGestureCaptured:)];
longTap.minimumPressDuration=0.5f;
longTap.delegate=self;
[myTableView addGestureRecognizer:longTap];
[super viewDidLoad];
}
-(void)longTapGestureCaptured:(UILongPressGestureRecognizer *)gesture
{
NSLog(#"Long tap"); // never called
}
However the longTapGestureCaptured is never called when I longpress. How can this be resolved ?
I tried your code. it's 100% working for me. But small change in your code is...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Create cell here
UITableViewCell *cell;
cell= (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
//Add gesture to cell here
UILongPressGestureRecognizer *longTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTapGestureCaptured:)];
longTap.minimumPressDuration=1.5f;
longTap.delegate=self;
[cell addGestureRecognizer:longTap];
cell.textLabel.text = #"Name";//Send your data here
return cell;
}
-(void)longTapGestureCaptured:(UILongPressGestureRecognizer *)gesture
{
NSLog(#"Long tap"); // never called
}
You add longPress even for UITableview. But when table have cells, cell of table will over on UITableView, so you can not longPress on TableView. Reslove for you is add longPress even on each Cell of Table. By add code add longPress even for each cell in function cellAtIndex. Good luck.
Related
I have a tableview with custom tableView cell present in it.
I have placed a UIImageview on custom tableViewCell. When i press or touch the imageView, i want to download some images from url, on the basis of selected index, which i am going to pass it(selectedIndex) as a string in the url.
What happens is when i first touch the image view, i am not getting the selected index path. But when i first select the cell and then i press the image view, at that time i get the selected index path. I searched it on the internet, but didn't found any appropriate solution. Here below is my code where i assign a UILongPressRecognizer to the UIImageView, in cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell.imgvDownload.tag=indexPath.row;
singleTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected12)];
[cell.imgvDownload setUserInteractionEnabled:YES];
[singleTap.delegate self];
[singleTap setMinimumPressDuration:0.01f];
[cell.imgvDownload addGestureRecognizer:singleTap];
return cell;
}
The problem is that UIImageview is to able to get the selected index path for the row selected. But if i first select any cell(row) from tableView and then press the UIImage view, i get the index.
Can anyone please tell me what wrong am i doing here. Any help is appreciated.
EDIT
I have slightly changed my code. Instead of using UIImageView and UILongPressGestureRecognizer, i am using a UIButton. And on press of that button i am trying to get the index path of the cell on which the button is present. Here Below is my new code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell.btnDownload.tag=indexPath.row;
return cell;
}
and the button press action method is-
-(IBAction)btnDownload:(id)sender{
UIView *sourceView = [sender view];
if ([sourceView isKindOfClass:[UIButton class]]) {
NSLog(#"row is %ld", sourceView.tag);
}
and on did select method i am storing the selected index path like this-
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
selectedIndex =[NSString stringWithFormat:#"%#%#",[[_shopDArrayFetched objectAtIndex:indexPath.section]valueForKey:#"ctid"],[[_shopDArrayFetched objectAtIndex:indexPath.section]valueForKey:#"scid"]];
NSLog(#"selectedIndex %#",selectedIndex);
}
and i want this index on my button click which i am not able to get.
Also the app is crashing on the line- UIView *sourceView = [sender view]; saying -[UIButton view]: unrecognized selector sent to instance
Any help or suggestions is appreciated.
I noticed you have restore indexPath.row in imageView, so all you need to do is in #selector(tapDetected12) get indexPath.row from imageView. Before you do this, there is one more thing to do: replace you #selector(tapDetected12) with #selector(tapDetected12:) the new parameter is a UIGestureRecognizer instance, from it you can get image view that user long pressed via UIGestureRecognizer's property #property(nullable, nonatomic,readonly) UIView *view.
Sample
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"reuseid" forIndexPath:indexPath];
cell.textLabel.text = self.datas[indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"someicon"];
cell.imageView.tag = indexPath.row;
UILongPressGestureRecognizer *singleTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected12:)];
[cell.imageView setUserInteractionEnabled:YES];
[singleTap.delegate self];
[singleTap setMinimumPressDuration:0.01f];
[cell.imageView addGestureRecognizer:singleTap];
return cell;
}
- (void)tapDetected12:(UIGestureRecognizer *)gestureRecognizer {
UIView *sourceView = gestureRecognizer.view;
if ([sourceView isKindOfClass:[UIImageView class]]) {
NSLog(#"row is %ld", sourceView.tag);
}
}
Snapshot
You can notice I select row 6 first(label text is 07), when I tap row 3(label text is 04), NSLog output is 3
Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// ...
cell.imgvDownload.userInteractionEnabled = YES;
UITapGestureRecognizer *imageTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTap:)];
[imageTapRecognizer setDelegate:self];
[cell.imgvDownload addGestureRecognizer:imageTapRecognizer];
cell.imgvDownload.tag = indexPath.row;
return cell;
}
- (void)imageTap:(UITapGestureRecognizer*)sender
{
UIView *view = sender.view;
NSLog(#"%ld", (long)view.tag); //By tag, you can find out where you had tapped.
}
I have a UITableView populated with cells that have buttons on them. I want those buttons to work also when in editing mode, but they don't. It seems like the gesture recognizer on UITableViewCell is preventing gesture recognizers on buttons. Does anyone have any suggestions about approaching this problem?
ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
self.items = [#[#"one", #"two", #"three", #"four"] mutableCopy];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: #"cellID"
forIndexPath:indexPath];
if (cell == nil) {
cell = [[TableViewCell alloc] init];
}
[cell.button setTitle: self.items[indexPath.row]
forState: UIControlStateNormal];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.items removeObjectAtIndex: indexPath.row];
}
}
TableViewCell.h:
#interface TableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *button;
- (IBAction)buttonTapped:(id)sender;
#end
So, the buttonTapped: is called when a cell isn't in editing mode, but when a cell is in editing mode, the button doesn't work.
Use different tags from each button in the cells. For example,
Inside cellforRowAtIndexPath, specify a tag for a button.
[Button addTarget:self action:#selector(func:event:) forControlEvents:UIControlEventTouchUpInside];
[Button setTag:indexPath.row];
Now call the function and refer the cell using tag.
-(IBAction)func:(id)sender event:(id)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint Pos = [touch locationInView:self.tableview];
NSIndexPath *indexPath = [self.tableview indexPathForRowAtPoint:Pos];
if(indexPath != nil){
//do operation with indexPath
}
}
Hope it helps...
First of all see some code what you have done !! without proper declaration its difficult to give answer.
Firstly My suggestion is give gesture recognize in UItableview delegate method.
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
// code
}
Sometimes gesture is not working with small mistake in coding.
Secondly if possible ,
Instead of adding the Gesture recognizer to the Cell directly, you can add it to the UItableview in viewDidLoad.
This is the best way to work gesture in UITableview.
As said by Phix in Example,
In the didSwipe-Method you can determine the affected IndexPath and cell as follows:
-(void)didSwipe:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
CGPoint swipeLocation = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *swipedIndexPath = [self.tableView indexPathForRowAtPoint:swipeLocation];
UITableViewCell* swipedCell = [self.tableView cellForRowAtIndexPath:swipedIndexPath];
// ...
}
}
You can set other gesture like as Above.
I hope it will solve your issue.
To do this, you need to subclass the UITableView and make it conform to a UIGestureRecognizerDelegate protocol. In .m file of your UITableView subclass add the following code:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass: [UIButton class]]) {
return NO;
}
return YES;
}
I'm a beginner to making iPhone app with Xcode6. (and excuse me non a native English speaker...)
setting up UITableView with customized cells (as another class, i.e. MyCustomCell)
I would like to show/hide a component (UIView) in customized cell class, when a cell in UITableView has a longpress (longTap) but stacked.
I could not know how to control (recognise) the target component on the same cell in customized cell class with indexPath (or something) some part of programs are as follows,
MyCustomCell.h
#interface MyCustomCell : UITableViewCell
#property (weak,nonatomic) IBOutlet UIView *customPanel;
UIViewController.m
#import “MyCustomCell.h"
********************************
- (void)viewDidLoad {
[super viewDidLoad];
[_tableView registerNib:[UINib nibWithNibName:#“MyCustomCell" bundle:nil] forCellReuseIdentifier:#"cell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
return cell;
}
-(void)longtapAction:(UILongPressGestureRecognizer *)gestureRecognizer {
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
if (indexPath == nil){
}else if (gestureRecognizer.state == UIGestureRecognizerStateBegan){
// I would like to change the hidden status of a UIVIEW in the CustomCell like
{self.customcell.custompanel:(indexPath).hidden = YES;}
}
}
Would you please let me know how to go over this trap ?
You need to create and assign a gestureRecognizer in to a cell:cellForRowAtIndexPath
UILongPressGestureRecognizer * recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTapAction:)];
recognizer.delegate = self;
[cell addGestureRecognizer:recognizer];
You can add the gesture-recogniser to the UITableView itself and then extract the target UITableViewCell on which the gesture was performed using something like this or this.
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 have UITableView that contains many cell. User can expand cell to see more content in this cell by push the expand button in this cell (only 1 cell can expand at time):
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(selectedRowIndex == indexPath.row) return 205;
else return 60;
}
In the storyboard, I drag UILongPressGesture into cell button and named it longPress (cell is custom, it has 2 buttons in it, 1 need to recognize LongPressGesture, the other expand cell height):
#property (retain, nonatomic) IBOutlet UILongPressGestureRecognizer *longPress;
And in the viewDidLoad:
- (void)viewDidLoad
{
[longPress addTarget:self action:#selector(handleLongPress:)];
}
It's work perfectly, however when I use following code to recognize cell indexPath, it's wrong when one cell is expanded:
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
// Get index path
slidePickerPoint = [sender locationInView:self.tableView];
NSIndexPath *indexPath= [self.tableView indexPathForRowAtPoint:slidePickerPoint];
// It's wrong when 1 cell is expand and the cell's button I hold is below the expand button
}
Can anyone please show me how to get correct indexPath when there're different cell height?
Thank in advance
One way to do it would be to add a UILongPressGestureRecognizer to each UITableViewCell (that all use the same selector), then when the selector is called you can get the cell via sender.view. Perhaps not the most memory efficient, but if the single gesture recognizer won't return the right row in certain situations, this way should work.
Something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
[longPress setMinimumPressDuration:2.0];
[cell addGestureRecognizer:longPress];
[longPress release];
return cell;
}
then
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
UITableViewCell *selectedCell = sender.view;
}
First add the long press gesture recognizer to the table view:
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
lpgr.minimumPressDuration = 2.0; //seconds
lpgr.delegate = self;
[self.myTableView addGestureRecognizer:lpgr];
[lpgr release];
Then in the gesture handler:
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
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
NSLog(#"long press on table view at row %d", indexPath.row);
}
}
You have to be careful with this so that it doesn't interfere with the user's normal tapping of the cell and also note that handleLongPress may fire multiple times before user lifts their finger.
Thanks...!