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.
Related
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
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I want to develop an app in which the items should be displayed as the UICollectionView. When user tap & hold the items all the items should start shaking like the Apple home screen on which icons start to shake when we want to delete an app. So please tell me how can I implement this feature. Is there any library can use?
Declare your variables first:
UIButton* _deleteButton;
CGPoint p; // It is a point which will give you which cell has been selected.
Add UIGestureRecognizerDelegate.
In .m file, in viewDidLoad, add UILongPressGestureRecognizer and UITapGestureRecognizer to your collectionView, since you want to shake the cells at long press:
- (void)viewDidLoad {
[super viewDidLoad];
// Add gesture recognizer to your collection view cell
UILongPressGestureRecognizer *lpgr
= [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
lpgr.minimumPressDuration = .3; // To detect after how many seconds you want shake the cells
lpgr.delegate = self;
[self.collectionView addGestureRecognizer:lpgr];
lpgr.delaysTouchesBegan = YES;
/// This will be helpful to restore the animation when clicked outside the cell
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleTap:)];
//lpgr.minimumPressDuration = .3; //seconds
tap.delegate = self;
[self.collectionView addGestureRecognizer:tap];
}
You can now implement handleLongPress: in your .m file. When you will long press your collectionViewCell, you will get (x,y) co-ordinates of where the user has pressed the cell, which we will store in point p.
Based on that point, you will be able to fetch the appropriate indexPath of the appropriate cell.
p = [gestureRecognizer locationInView:self.collectionView]; // Store (x,y) co-ordinate where the user has tapped the cell in point p.
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
Now, give animation to the cell, which has been tapped using CABasicAnimation of QuartzCore framework. At the time of animation, bring your _deleteButton up so that it is visible.
With handleTap:, you will then be able to restore animation when clicked outside of the collectionViewCell.
-(void)handleTap:(UITapGestureRecognizer *)gestureRecognizer
{
NSLog(#"singleTap");
if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
return;
}
p = [gestureRecognizer locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
if (indexPath == nil){
NSLog(#"couldn't find index path");
[[NSUserDefaults standardUserDefaults]setValue:#"no" forKey:#"longPressed"];
[[NSUserDefaults standardUserDefaults]setValue:#"yes" forKey:#"singleTap"];
//_deleteButton = [[UIButton alloc] initWithFrame:CGRectZero];
//[cell addSubview:_deleteButton];
//[_deleteButton removeFromSuperview];
[self.collectionView reloadData];
} else {
}
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
return;
}
p = [gestureRecognizer locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
if (indexPath == nil){
NSLog(#"couldn't find index path");
} else {
[[NSUserDefaults standardUserDefaults]setValue:#"yes" forKey:#"longPressed"];
[self.collectionView reloadData];
}
}
Based on the selected item, delete the appropriate item.
-(void)deleteyourItem
{
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
//delete your item based on the `indexpath` from your collectionViewArray here.
//OR If you are accessing the database to display the collectionView, you can compare the value fetched based on the `indexPath`, with your database value and then delete it.
// Reload your collectionView after deletion
}
After you reload the collection view, cellForItemAtIndexPath:, will look like this:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"favoritecell" forIndexPath:indexPath];
// UIImageView *img=[[UIImageView alloc]init];
cell.backgroundColor = [UIColor colorWithRed:251.0/255.0 green:144.0/255.0 blue:13.0/255.0 alpha:1.0];
//img.image = [UIImage imageNamed:#""];
NSLog(#"%d",indexPath.row);
if([[[NSUserDefaults standardUserDefaults]valueForKey:#"longPressed"] isEqualToString:#"yes"])
{
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
[anim setToValue:[NSNumber numberWithFloat:0.0f]];
[anim setFromValue:[NSNumber numberWithDouble:M_PI/64]];
[anim setDuration:0.1];
[anim setRepeatCount:NSUIntegerMax];
[anim setAutoreverses:YES];
cell.layer.shouldRasterize = YES;
[cell.layer addAnimation:anim forKey:#"SpringboardShake"];
CGFloat delButtonSize = 75;
_deleteButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, delButtonSize, delButtonSize)];
_deleteButton.center = CGPointMake(0, 0);
_deleteButton.backgroundColor = [UIColor clearColor];
[_deleteButton setImage: [UIImage imageNamed:#"delete.png"] forState:UIControlStateNormal];
[cell addSubview:_deleteButton];
[_deleteButton addTarget:self action:#selector(deleteRecipe) forControlEvents:UIControlEventTouchUpInside];
}
else if ([[[NSUserDefaults standardUserDefaults]valueForKey:#"singleTap"] isEqualToString:#"yes"])
{
for(UIView *subview in [cell subviews]) {
if([subview isKindOfClass:[UIButton class]]) {
[subview removeFromSuperview];
} else {
// Do nothing - not a UIButton or subclass instance
}
}
[cell.layer removeAllAnimations];
// _deleteButton.hidden = YES;
// [_deleteButton removeFromSuperview];
}
//251, 144 , 13
return cell;
}
hi iam developing a social networking application using UICollectionview horizontal layout, when ever my app launches collection view loads up to 5 cells then if i swipe 5th cell then that time only 6th cell memory will allocates. same way swipe 6th cell to 7 th cell like that.So,how can i implement this process
thanks in advance for any advices
You need to add a swipe gesture recognizer to your collectionView:
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionUp;
[collectionView addGestureRecognizer:swipeGesture];
Then, handle the swipe in handleSwipeGesture: to allocate the cell.
-(void) handleSwipeGesture:(UISwipeGestureRecognizer *) sender
{
...
}
You can make the swipe direction whatever you want to use, this one is configure for up.
That's pretty much all there is to it. Main thing is you don't want the direction to conflict with the scrolling direction swipe, as I don't think there is a clean way to deal with that. When you are scrolling horizontally, that is a swipe, so you would need to use up/down swipe direction.
To attach to the cell instead (to capture gesture on an individual cell) I do it most times for simple collectionviews in the following method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
...
UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
[cell addGestureRecognizer:longPressGestureRecognizer];
...
}
(This is a long press, but it works the same way). In the case of putting it in the cell, you'll need to put a tag on the cell then reference that tag int the handler to figure out which cell it came from:
Here's one for the above:
- (void) handleLongPress: (UILongPressGestureRecognizer *) sender
{
if (sender.state != UIGestureRecognizerStateBegan)
return;
CGPoint p = [sender locationInView: collectionView];
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:p];
if (indexPath != nil)
{
UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
if (cell)
{
int indexOfItem = cell.tag;
NSLog(#"Selected item = %d", indexOfItem);
}
}
At least something along this line...
You can achieve this by implement the UIScrollViewDelegate method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint offset = scrollView.contentOffset;
CGRect bounds = scrollView.bounds;
CGSize size = scrollView.contentSize;
UIEdgeInsets inset = scrollView.contentInset;
float y = offset.x + bounds.size.width - inset.right;
float h = size.width;
float reload_distance = 75; //distance for which you want to load more
if(y > h + reload_distance) {
// write your code getting the more data
NSLog(#"load more rows");
}
}
in this when you go at the last cell of the collection then this scroll view delegate method will called.
and you may change the distance vale according to your requirement.
in my app i have a UICollectionView. i want to apply to it's cells a long pressure gesture. i implemented that but when i run the app only the last cell works and the others do not respond. what it wrong? here is my code.
#interface
#property (nonatomic, strong) UILongPressGestureRecognizer *longPressure;
in view did load:
self.longPressure = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handlePressue:)];
self.longPressure.delegate = self;
[self.collectionView addGestureRecognizer:self.longPressure];
gesture handler:
- (void)handlePressue:(UILongPressGestureRecognizer*)gesture{
[[gesture.view viewWithTag:1] setBackgroundColor:[UIColor yellowColor]];
}
in collectionView:cellforitemAtIndexPAth:
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 75, 75)];
imageView.tag = 1;
[imageView setBackgroundColor:[UIColor redColor]];
[cell addGestureRecognizer:self.longPressure];
[cell addSubview:imageView];
return cell;
is there anything wrong?
you need to add gesture on the each cell not for the UICollection View. that might be your problem.the last cell works because the gesture is added to the last cell only.
You need to creat long press gesture for each cell. Because gesture like other ui control,only one in the project.If you want add it to other view,you need copy another one.
Have a look at following Code snippet
MyFlowLayout *myLayout = [[MyFlowLayout alloc]init];
[self.collectionView setCollectionViewLayout:myLayout animated:YES];
UIGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc]
}
initWithTarget:self action:#selector(handlePinch:)];
[self.collectionView addGestureRecognizer:pinchRecognizer];
Handling the Pinch:
- (IBAction)handlePinch:(UIPinchGestureRecognizer *)sender {
// Get a reference to the flow layout
MyFlowLayout *layout =
(MyFlowLayout
*)self.collectionView.collectionViewLayout;
// If this is the start of the gesture
if (sender.state == UIGestureRecognizerStateBegan) {
// Get the initial location of the pinch?
CGPoint initialPinchPoint =
[sender locationInView:self.collectionView]; //Convert pinch location into a specific cell
NSIndexPath *pinchedCellPath =
[self.collectionView
indexPathForItemAtPoint:initialPinchPoint];
// Store the indexPath to cell
layout.currentCellPath = pinchedCellPath; }
else if (sender.state == UIGestureRecognizerStateChanged) {
// Store the new center location of the selected cell layout.currentCellCenter =
[sender locationInView:self.collectionView]; // Store the scale value
layout.currentCellScale = sender.scale; }
else {
[self.collectionView performBatchUpdates:^{ layout.currentCellPath = nil;
layout.currentCellScale = 1.0;
} completion:nil];
} }
For performance reasons I suggest you to avoid adding subviews and/or gestures to every single cell. Instead, add a singe longPressureGesture to your collectionView and on the gesture selector handle your per-cell switch business logic. Something as follow:
On your viewDidLoad or where you setup your collection, add the following gesture:
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(showDeleteActions:)];
longPress.delegate = self;
[_aCollectionView addGestureRecognizer:longPress];
then on the selector do the single-cell handling:
- (void)showDeleteActions:(UILongPressGestureRecognizer*)gesture {
if (gesture.state == UIGestureRecognizerStateBegan)
{
NSIndexPath *indexPath = [_aCollectionView indexPathForItemAtPoint:[gesture locationInView:_aCollectionView]];
UICollectionViewCell *cell = [_aCollectionView cellForItemAtIndexPath:indexPath];
NSLog(#"cell to delete at IndexPath: %#", indexPath);
}
}
this approach is much more efficient abd far more stable.
Here what it is causing that your UILongPressGestureRecognizer getting overwrite to last cell. So you need to create UILongPressGestureRecognizer for each cell in cellForRowAtIndexPath:
Here is a small code snippet that can help you out
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 75, 75)];
imageView.tag = 1;
[imageView setBackgroundColor:[UIColor redColor]];
UILongPressGestureRecognizer *longPressure =[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handlePressue:)];
longPressure.delegate = self;
cell.userInteractionEnabled = YES; // Make userInteractionEnabled enable so it can detect touch
[cell addGestureRecognizer:self.longPressure];
[cell addSubview:imageView];
return cell;
There is no need to create any property for the UILongPressGestureRecognizer in .h file. And also remove code to add userInteractionEnabled on whole UICollectionView.
This question already has answers here:
Getting row of UITableView cell on button press
(10 answers)
Closed 9 years ago.
I have a custom method to detect a tap on a cell's image. I want to also find the index path of the image's correlating cell, and use it within the function. Here is what I am using:
CellforRowAtIndexPath:
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(cellImageTapped:)];
tapped.numberOfTapsRequired = 1;
[cell.imageView addGestureRecognizer:tapped];
method im trying to get the index path at:
-(void)cellImageTapped:(id)sender {
if(videoArray.count > 0){
Video *currentVideo = [videoArray objectAtIndex:INDEX_PATH_OF_CELL_IMAGE];
//do some stuff
}
}
I have no idea how to pass the index path. Any ideas?
Simple way:
Get the point of touch
Then get index path of cell at point
The code is:
-(void)cellImageTapped:(id)sender {
UITapGestureRecognizer *tap = (UITapGestureRecognizer *)sender;
CGPoint point = [tap locationInView:theTableView];
NSIndexPath *theIndexPath = [theTableView indexPathForRowAtPoint:point];
if(videoArray.count > 0){
Video *currentVideo = [videoArray objectAtIndex:theIndexPath];
//do some stuff
}
}
I would recommend this way to fetch indexPath of cell which has custom subview - (compatible with iOS 7 as well as all previous versions)
- (void)cellImageTapped:(UIGestureRecognizer *)gestureRecognizer
{
UIView *parentCell = gestureRecognizer.view.superview;
while (![parentCell isKindOfClass:[UITableViewCell class]]) { // iOS 7 onwards the table cell hierachy has changed.
parentCell = parentCell.superview;
}
UIView *parentView = parentCell.superview;
while (![parentView isKindOfClass:[UITableView class]]) { // iOS 7 onwards the table cell hierachy has changed.
parentView = parentView.superview;
}
UITableView *tableView = (UITableView *)parentView;
NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)parentCell];
NSLog(#"indexPath = %#", indexPath);
}
Add a tag to the UIImageView in your UITableViewDataSource's tableView:cellForRowAtIndexPath: method.
cell.imageView.tag = indexPath.row;
I ended up using the sender's view's tag. Hopefully this will help someone, as I wasted an hour finding the answer.
-(void)cellImageTapped:(id)sender {
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
if(videoArray.count > 0){
NSInteger datIndex = gesture.view.tag;
Video *currentVideo = [videoArray objectAtIndex:datIndex];
}
}
Use the delegate method didSelectRowAtIndexPath: method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self cellImageTapped:indexPath];
}
Then you can pass the index to a function i.e.
-(void)cellImageTapped:(NSIndexPath *)indexPath
{
Video *currentVideo = [videoArray objectAtIndex:indexPath.row];
}