9

I am trying to get the touch location inside the selected UICollectionviewCell. I have a UIViewController, vc, containing a UICollectionView, collectionView, as its view. Inside the collectionView are UICollectionViewCells. The vc conforms to the UICollectionViewDelegate so preferably I would like to get the touched location inside the delegate callback, collectionView:(UICollectionView *)collection didSelectItemAtIndexPath:(NSIndexPath *)indexPath, (if possible). Any recommendation on how to do that? Thanks.

+--------------------------------------------+
| UICollectionView                           |
|                                            |
|  +-------------+       +-------------+     |
|  |  UICollec   |       |             |     |
|  |  tionView   |       |             |     |
|  |  Cell       |       |     *<---------------<Touch here
|  |             |       |             |     |
|  +-------------+       +-------------+     |
|                                            |
+--------------------------------------------+    

*UPDATE* I ended up detecting the tap on the UIViewCollectionView using the UIGestureRecognizer and then converting the tap point to the UICollectionViewCell view. Please let me know if there's a better way. Thanks.

-(void) viewDidLoad {
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    [tapGesture setNumberOfTapsRequired:1];
    [self.collectionView addGestureRecognizer:tapGesture];
}

-(void) handleTap:(UIGestureRecognizer*) gesture {
    if (gesture.state == UIGestureRecognizerStateEnded) {
    CGPoint tappedPoint = [gesture locationInView:_collectionView];
    NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:tappedPoint];
    CollectionViewCell *cell = (CollectionViewCell*)[self.collectionView cellForItemAtIndexPath:indexPath];
    CGPoint pointWRTCell = [cell convertPoint:tappedPoint fromView:self.collectionView];
    NSLog(@"collectionView point(%1.1f,%1.1f); cell point (%1.1f,%1.1f)",
          tappedPoint.x,tappedPoint.y,pointWRTCell.x,pointWRTCell.y);
    }
}
MobileDev
  • 3,750
  • 4
  • 32
  • 35

4 Answers4

6

You will likely need a custom cell to do this. didSelectItemAtIndexPath only tells you a cell was selected. Not where inside the cell it was touched.

CrimsonChris
  • 4,651
  • 2
  • 19
  • 30
  • Thanks for your response. Subclassing 'UICollectionView' might work. I ended up using the 'UITabGestureRecognizer' and convert the tapped location from the 'UICollectionView' to 'UICollectionViewCell' – MobileDev Apr 08 '14 at 05:46
  • Some context might help us come up with a better solution. What is the problem you are trying to solve? – CrimsonChris Apr 08 '14 at 05:52
  • I simply want to delete a cell when a user tab a specific location of a cell (not the cell itself) – MobileDev Apr 08 '14 at 05:56
  • Ah! The simplest thing would probably be to create a custom UICollectionViewCell that contains a button and has a weak delegate reference. Have your controller be the delegate. The cell could have an indexPath property (make sure to set it in cellForRowAtIndexPath every time to avoid cell reuse bugs). When the button is pressed have it call a method on the delegate (something like `deleteButtonPressed:(id)sender atIndexPath:(NSIndexPath *)indexPath;`) – CrimsonChris Apr 08 '14 at 06:02
  • Just saw your update. That solution seems a little fragile but I guess it keeps you from subclassing which is always nice. I once accomplished something like this without subclassing by adding my button at runtime and attaching the index path as an associated property on the UITableViewCell. – CrimsonChris Apr 08 '14 at 06:14
1

UIView has a method func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView?. To get the touch point, you can override this method in your collection view or collection view cell.

And there are methods like func convertPoint(_ point: CGPoint, toView view: UIView?) -> CGPoint for you to convert point in different coordinate systems.

Jaybo
  • 944
  • 10
  • 13
1

Get indexPath to try this code..

(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CellId" forIndexPath:[indexPath row]]; 

[[cell myButton] addTarget:self action:@selector(myClickEvent:event:) forControlEvents:UIControlEventTouchUpInside];

return cell;

}


(IBAction)myClickEvent:(id)sender event:(id)event {

NSSet *touches = [event allTouches];

UITouch *touch = [touches anyObject];

CGPoint currentTouchPosition = [touch locationInView:_myCollectionArray];

NSIndexPath *indexPath = [_myCollectionArray indexPathForItemAtPoint: currentTouchPosition];

}
bhadresh
  • 445
  • 5
  • 15
0

You should add the property for saving the touch location in the UICollectionViewCell.

@interface YourCollectionViewCell : UICollectionViewCell
@property (nonatomic, assign) CGPoint       touchPoint;
@end

Then add the event of touchesBegan in YourCollectionViewCell.m

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    self.touchPoint = [[touches anyObject] locationInView:self];
}

Finally, you may use the touchPoint in your UICollectionView

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    YourCollectionViewCell * cell = [collectionView cellForItemAtIndexPath:indexPath];
    NSLog(@"touch location %f, %f", cell.touchPoint.x, cell.touchPoint.y);
}

I think it's the easier way to get the touch location. And I'm using it in my codes.

evolrof
  • 1
  • 1