TableView indexPathForRowAtPoint returns row index 0 - ios

I have problem with receiving right NSIndexPath in gesture recognizer selector.
In UITableViewController:viewDidLoad im initializing gesture recognizer
UISwipeGestureRecognizer* rightSwipeGestureRecognizer =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRight:)];
rightSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.tableView addGestureRecognizer:rightSwipeGestureRecognizer];
In gesture handler im trying to get row index:
- (void) swipeRight: (UISwipeGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
CGPoint swipeLocation = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *swipedIndexPath = [self.tableView indexPathForRowAtPoint:swipeLocation];
NSInteger row = swipedIndexPath.row;
NSLog(#"Row %d", swipedIndexPath.row);
}
CGPoint is correct but row is always 0. Any idea why ?

Add a UISwipeGestureRecognizer to each UITableViewCell (with same selector). Then when the selector is called you can get the cell via: sender.view.

Related

How to detect tap only on cells not on whole collection view?

I have collectionView in my app. I have a requirement that I should be able to both double & single tap on cells to perform diffrent operations. To make it possible both double & single tap gesture on the collectionView I have added both the gesture on collection view & got the location by below code.
-(void)handleSingleTap:(UITapGestureRecognizer *)gestureRecognizer
{
if([arr_userAlbums count]>0)
{
if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
{
return;
}
p = [gestureRecognizer locationInView:self.collection_view];
NSIndexPath *indexPath = [self.collection_view indexPathForItemAtPoint:p];
celltTapped_index_path=indexPath;
}
}
-(void)handleDoubleTap:(UITapGestureRecognizer *)gestureRecognizer
{
if([arr_userAlbums count]>0)
{
if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
{
return;
}
p = [gestureRecognizer locationInView:self.collection_view];
NSIndexPath *indexPath = [self.collection_view indexPathForItemAtPoint:p];
celltTapped_index_path=indexPath;
}
}
But in this case the whole screen even where cells are not visible it is accepting the double tap & single tap. I want to detect single & double tap only on cells not the whole collection view.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cvCell";
customCell *cell = (customCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.img_Collection.image = [imgArray objectAtIndex:indexPath.row];
cell.lbl_Collection.text = [lblArray objectAtIndex:indexPath.row];
cell.tag = indexPath.row;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
singleTap.delaysTouchesEnded = YES;
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
doubleTap.numberOfTapsRequired = 2;
[singleTap requireGestureRecognizerToFail:doubleTap];
[cell addGestureRecognizer:singleTap];
[cell addGestureRecognizer:doubleTap];
return cell;
}
-(void)handleSingleTap:(UIGestureRecognizer *)recognizer
{
NSLog(#"The single tap happened for %ld th index",recognizer.view.tag);
}
-(void)handleDoubleTap:(UIGestureRecognizer *)recognizer
{
NSLog(#"The Double tap happened for %ld th index",recognizer.view.tag);
}
you can get tapped View by using hitTest Method like this
UIView *tappedView = [self hitTest:yourLocation forEvents:nil];
This will return you the view which is tapped
Check this with if condition like this
if(tappedView == Imageview)
{
// do this
}
else if(tappedView == CollectionViewCell)
{
// do this
}

How to handle the event for the UICollectionView custom cell?

I have created a custom cell for the UICollectionView. The custom cell has two UIImageView - imageView1 and imageView2.
How should I handle the event for each imageView? I can get handle only the cell event on didSelectedItemIndex delegate of UICollectionView. I want to get handle for each imageView.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotosViewCell *cell = (PhotosViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
int tag1 = cell.imageView1.tag;
int tag2 = cell.imageview2.tag;
....
}
In your cellForRowAtIndexPath method define tap gesture recognizer with selector and assign it to your image.
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(productImageTap:)];
[cell.imageView1 addGestureRecognizer:tapGesture];
[cell.imageView1 setUserInteractionEnabled:YES];
[cell.imageView2 addGestureRecognizer:tapGesture];
[cell.imageView2 setUserInteractionEnabled:YES];
Then you can do anything you want in productImageTap method. Just get indexPath via locationInView method..
- (void)productImageTap:(UITapGestureRecognizer *)gesture
{
CGPoint point = [gesture locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
PhotosViewCell *cell = (PhotosViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
//do whatever you want with cell properties..
}

How to get the location of the UICollectionViewCell in self.view?

I used the code below to get the location of the cell when touched.
However, when the UICollectionView.bounds.size.width > 320, or > 640, the "origin.x" returned often > 320, for example, 657, 469. Cause there are some images inside cells. So when I touched the cell on the second page. The value X returned may be 368.0 or other values.
I just need to get the value X in the current view.(320 * 480).
UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath];
- (void)viewDidLoad
{
// attach long press gesture to collectionView
UILongPressGestureRecognizer *lpgr
= [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
lpgr.minimumPressDuration = .5; //seconds
lpgr.delegate = self;
[self.collectionView addGestureRecognizer:lpgr];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
return;
}
CGPoint p = [gestureRecognizer locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
if (indexPath == nil){
NSLog(#"couldn't find index path");
} else {
// get the cell at indexPath (the one you long pressed)
UICollectionViewCell* cell =
[self.collectionView cellForItemAtIndexPath:indexPath];
// do stuff with the cell
}
}
If I understand your question correctly, your collection view may have multiple pages horizontally. Assuming these pages are frame-width, you could do this:
int xVal = (int)p.x % (int)self.view.frame.size.width;
Keep in mind that you will lose decimal precision.

Making UITextField in prototype cell first responder

I have set up the textfield with a tag and user interaction disabled in a prototype cell.
This is how I have created the cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
..
..
..
UILongPressGestureRecognizer *longPressgesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(LongPressgesture:)];
[longPressgesture setMinimumPressDuration:2.0];
[cell.contentView addGestureRecognizer: longPressgesture];
UITextField *toDoTextField = (UITextField *)[cell.contentView viewWithTag:1];
toDoTextField.tag = indexPath.row;
return cell;
}
then I would like to edit the textfield after a long press. So I have this:
- (void)LongPressgesture:(UILongPressGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded) {
}
else {
UITableView* tableView = (UITableView*)self.view;
CGPoint touchPoint = [recognizer locationInView:self.view];
NSIndexPath* row = [tableView indexPathForRowAtPoint:touchPoint];
NSInteger rowRow = [row row];
UITextField *toDoTextField = (UITextField *)[cell.contentView viewWithTag:rowRow];
toDoTextField.userInteractionEnabled = YES;
[toDoTextField becomeFirstResponder];
}
When I trigger the long press though only the last cell will work. Not sure what I'm doing wrong.
I would like to be able to long press on any cell and then edit the text.
Thank you if you can help.
Add the long press gesture recognizer to the table view not the cell:
UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
recognizer.minimumPressDuration = 2.0;
[self.myTableView addGestureRecognizer:recognizer];
Then handle it like this:
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (recognizer.state != UIGestureRecognizerStateEnded)
return;
CGPoint p = [gestureRecognizer locationInView:self.myTableView];
NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
if (!indexPath)
NSLog(#"Long press was on tableView, but not on a row");
else
{
NSLog(#"Long press on table view # row %d", indexPath.row);
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
NSAssert(cell, #"Cell must be found");
if (!cell)
return;
UITextField *toDoTextField =
(UITextField *)[cell.contentView viewWithTag:indexPath.row];
NSAssert(toDoTextField, #"UITextField must be found by tag");
if (toDoTextField)
{
[self.tableView endEditing:YES];
toDoTextField.userInteractionEnabled = YES;
[toDoTextField becomeFirstResponder];
}
}
}

iOS - indexPathForRowAtPoint don't return correct indexPath with different cell height

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...!

Resources