I have UICollectionView on which contains so many custom cells.I have a long press gesture on it when user long press then cells start shaking & delete button is added on them.When i press the delete button then cell is removed from collection view.
Code for long press.
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
p = [gestureRecognizer locationInView:self.collection_view];
NSIndexPath *indexPath = [self.collection_view indexPathForItemAtPoint:p];
if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
{
return;
}
if (indexPath == nil)
{
NSLog(#"couldn't find index path");
}
else
{
[[NSUserDefaults standardUserDefaults]setValue:#"yes" forKey:#"longPressed"];
[self.collection_view reloadData];
}
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
NSLog(#"UIGestureRecognizerStateEnded");
//Do Whatever You want on End of Gesture
}
else if (gestureRecognizer.state == UIGestureRecognizerStateBegan){
NSLog(#"UIGestureRecognizerStateBegan.");
//Do Whatever You want on Began of Gesture
}
pgr
= [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handePanPress:)];
// To detect after how many seconds you want shake the cells
pgr.delegate = self;
[self.collection_view addGestureRecognizer:pgr];
//show the done button here
navButtonDone = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStylePlain target:self action:#selector(navBtnDone:)];
self.navigationItem.rightBarButtonItem = navButtonDone;
}
when long gesture start i also add the right button on nav bar on press of nav bar button i stop animation & remove the delete button.I able to remove delete button in iPhone 5s but not in iPhone 6.
below is code for that
- (IBAction)navBtnDone:(id)sender
{
if([[[NSUserDefaults standardUserDefaults]valueForKey:#"longPressed"] isEqualToString:#"yes"])
{
[[NSUserDefaults standardUserDefaults]setValue:#"no" forKey:#"longPressed"];
[_deleteButton removeFromSuperview];
[self.collection_view reloadData];
[self.collection_view removeGestureRecognizer:pgr];
self.navigationItem.rightBarButtonItem=nil;
}
}
Here i have just added [_deleteButton removeFromSuperview]; how can i get cell in each function & remove the delete button.
To retrieve the cell based on its indexpath you can call
UICollectionViewCell *someCell = [myCollectionView cellForItemAtIndexPath:indexPath];
Then remove the delete button with
if (someCell) {
// Remove the delete button on the cell.
[someCell.deleteButton removeFromSuperView];
}
There are two ways.
To Store the IndexPath in a global variable.
In your .h
NSIndexPath *globalIndexPath
In your Gesture Recogniser
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
p = [gestureRecognizer locationInView:self.collection_view];
globalIndexPath = [self.collection_view indexPathForItemAtPoint:p];
//Other Stuff
}
In your Delete button action
- (IBAction)navBtnDone:(id)sender
{
//Other Stuff
UICollectionViewCell *cell = [myCollectionView cellForItemAtIndexPath: globalIndexPath];
if (cell) {
[cell.deleteButton removeFromSuperView];
}
}
Set the Indexpath.row value to the Barbutton's tag value
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
p = [gestureRecognizer locationInView:self.collection_view];
NSIndexPath *indexPath = [self.collection_view indexPathForItemAtPoint:p];
//Other Stuff
//show the done button here
navButtonDone = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStylePlain target:self action:#selector(navBtnDone:)];
navButton.tag = indexPath.row //IMPORTANT
self.navigationItem.rightBarButtonItem = navButtonDone;
}
In your Button Action
- (IBAction)navBtnDone:(id)sender
{
UIBarButtonItem *btn = (UIBarButtonItem *)sender;
UItableViewCell *cell = [myCollectionView cellForItemAtIndexPath: [NSIndexPath indexPathWithRow: btn.tag inSection:0]];
[cell.deleteButton removeFromSuperView];
}
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
}
Wondering how can I get all items of each cell in UITableView. My problem is that I want to hide 2 buttons in cell when third is selected.
When I press on button 1, button 2 and 3 must be hidden. What I tried to do for that (in cellForRowAtIndexPath) :
AVMMovieButton *settings = (AVMMovieButton *)[cell viewWithTag:228];
[settings addTarget:self action:#selector(selectSettings:) forControlEvents:UIControlEventTouchUpInside];
settings.tag = indexPath.row;
AVMMovieButton *playButton = (AVMMovieButton *)[cell viewWithTag:134];
[playButton setStore:oneItem];
[playButton addTarget:self action:#selector(playMovie:) forControlEvents:UIControlEventTouchUpInside];
playButton.tag = indexPath.row;
AVMMovieButton *down = (AVMMovieButton *)[cell viewWithTag:282];
AVMMovieButton *del = (AVMMovieButton *)[cell viewWithTag:161];
[settings setSelected:!settings.isSelected];
if (settings.isSelected)
{
NSLog(#"SELECTED!");
down.hidden = YES;
del.hidden = YES;
downLabel.hidden = YES;
delLabel.hidden = YES;
// [self performSelector:#selector(playButtonShow) withObject:nil afterDelay:0.3];
playButton.hidden = NO;
}
else
{
NSLog(#"UNSELECTED!");
playButton.hidden = YES;
down.hidden = NO;
del.hidden = NO;
downLabel.hidden = NO;
delLabel.hidden = NO;
NSLog(#"play button %d",playButton.hidden);
}
and then I added method for selecting my "settings" button:
-(void)selectSettings:(AVMMovieButton *)sender
{
[sender setSelected:!sender.isSelected];
NSLog(#"you just select button");
}
but it doesn't work!
Actually NSLog(#"you just select button"); works, but buttons never hides.
What should I do to get my buttons and hide them?
SOLVED:
All I needed to do was to create custom UITableViewCell class and then access my cell as Jay Gajjar and Akhilrajtr said. After I just used my method for select/deselect my button.
What I've got:
-(void)selectSettings:(AVMMovieButton *)sender
{
AVMMovieButton *settings = (AVMMovieButton *)sender;
CGPoint pointInTable = [settings convertPoint:settings.bounds.origin toView:readyTable];
NSIndexPath *indexPath = [readyTable indexPathForRowAtPoint:pointInTable];
AVMMovieCell *cell=(AVMMovieCell *)[readyTable cellForRowAtIndexPath:indexPath];
if (cell.settingsButton.isSelected)
{
NSLog(#"SELECTED!");
cell.downloadButton.hidden = YES;
cell.deleteButton.hidden = YES;
cell.downLabel.hidden = YES;
cell.delLabel.hidden = YES;
cell.playButton.hidden = NO;
}
else
{
NSLog(#"UNSELECTED!");
cell.playButton.hidden = YES;
cell.downloadButton.hidden = NO;
cell.deleteButton.hidden = NO;
cell.downLabel.hidden = NO;
cell.delLabel.hidden = NO;
NSLog(#"play button %d",cell.playButton.hidden);
}
[settings setSelected:!settings.isSelected];
}
Hope this can be helpful for somebody else!
Try this,
-(void)selectSettings:(AVMMovieButton *)sender{
[sender setSelected:!sender.isSelected];
CGPoint pointInTable = [sender convertPoint:sender.bounds.origin toView:_tableView];
NSIndexPath *indexPath = [_tableView indexPathForRowAtPoint:pointInTable];
[_tableView beginUpdates];
[_tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[_tableView endUpdates];
NSLog(#"you just select button");
}
cellForRowAtIndexPath is called when Table get reloaded. In your case, what you have to do is:
- (void)button3Method:(id)sender
{
// Begin UITableView Update
[self.tableView beginUpdates];
NSIndexPath *indexPath = // Get cell indexpath for the selected row.
// Logic for getting the UITableViewCell on which you want hide two buttons.
// Logic for hiding those two buttons
// Below line performs reloading of particular UITableViewCell.
[self.tableView reloadRowsAtIndexPaths:#[indexPathOfYourCell] withRowAnimation:UITableViewRowAnimationNone];
// End UITaleView Update
[self.tableView endUpdates];
}
Let me know, if this works for you. Good luck.
In cellForRowAtIndexPath:
[cell. settings addTarget:self action:#selector(selectSettings:) forControlEvents:UIControlEventTouchUpInside];
cell. settings.tag=600+indexPath.row;
In button IBAction:
-(void) selectSettings:(id) sender{
UIButton *btn=(UIButton *)sender;
cellMoreButtonIndex=btn.tag;
YOURCELL *cell=(YOURCELL *)[self.contentTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:btn.tag-600 inSection:0]];
[settings setSelected:!settings.isSelected];
if (settings.isSelected) {
NSLog(#"SELECTED!");
down.hidden = YES;
del.hidden = YES;
downLabel.hidden = YES;
delLabel.hidden = YES;
// [self performSelector:#selector(playButtonShow) withObject:nil afterDelay:0.3];
playButton.hidden = NO;
}else {
NSLog(#"UNSELECTED!");
playButton.hidden = YES;
down.hidden = NO;
del.hidden = NO;
downLabel.hidden = NO;
delLabel.hidden = NO;
NSLog(#"play button %d",playButton.hidden);
}
}
add a custom cell and Handle button click event and hide/unhide functionality on cell level
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];
}
}
}
i am trying to use UIMenuController to perform a custom action on the table cell, from which the UIMenuController triggered by long time press.
I registered UILongPressGestureRecognizer in the viewDidLoad method in my subclass of UITableViewController and added custom item with #selector(handleMyAction).
- (void)viewDidLoad
{
[super viewDidLoad];
[self.refreshControl addTarget:self action:#selector(refreshView:) forControlEvents:UIControlEventValueChanged];
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
longPressGesture.minimumPressDuration = .5;
longPressGesture.delegate = self;
[self.tableView addGestureRecognizer:longPressGesture];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint point = [gestureRecognizer locationInView:self.tableView];
NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
if(indexPath == nil) return ;
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIMenuItem *it = [[UIMenuItem alloc] initWithTitle:#"My Action on this cell" action:#selector(handleMyAction:)];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:[NSArray arrayWithObjects:it, nil]];
[menu setTargetRect:cell.frame inView:cell.superview];
[menu setMenuVisible:YES animated:YES];
[self becomeFirstResponder];
}
}
I also override the
- (BOOL)canBecomeFirstResponder{
return YES;
}
When I press on one cell the context menu with the custom entry displays properly. BUT, the problem is how can I implement the method to handle the custom action, which should be performed on the tapped cell.
- (void)handleMyAction:(id)sender
{
NSLog(#"Action triggered, however need some way to refer the tapped cell");
}
Because the only information i can get in this method is the sender, which is the UIMenuController self, but i have no idea how can get the cell, on which the Menu triggered, so i can do further action regarding the cell itself.
Could some one help me on that?
Thanks.
Hai
Well you're currently adding the UIGestureRecognizer to the tableview itself. Why not add it to each cell instead (in cellForRowAtIndexPath when they are setup) ?
Thanks valheru. I find a "nice" approach to achieve that:)
Step one: In MyTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
longPressGesture.minimumPressDuration = .5;
longPressGesture.delegate = self;
[self.view addGestureRecognizer:longPressGesture];
}
which register the gesture recognizer of the long press on the table view controller.
- (BOOL)canBecomeFirstResponder
{
return YES;
}
which allows MyTableViewController response the long press and popup the context menu.
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint point = [gestureRecognizer locationInView:self.tableView];
NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
if(indexPath == nil) return ;
MyCell *cell = (MyCell *)[self.tableView cellForRowAtIndexPath:indexPath];
UIMenuItem *determine = [[UIMenuItem alloc] initWithTitle:#"My Action on this cell" action:#selector(handleMyAction:)];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:[NSArray arrayWithObjects:determine, nil]];
[menu setTargetRect:cell.frame inView:cell.superview];
[menu setMenuVisible:YES animated:YES];
[cell becomeFirstResponder]; //here set the cell as the responder of the menu action
cell.delegate = self;// this is optional, if you don't want to implement logic in cell class
}
}
create the UIMenuController and popup when i long press the cell.
-(void)handleMyAction: (UITableViewCell *)cell
{
NSLog(#"%#", cell);
}
this function will be called later from the cell which is pressed.
Step two: Create a subclass of UITableViewCell named MyCell
In MyCell.h defines the table view controller the cell belongs as the delegate of the cell. And the callback function when the menu entry clicked
#property (nonatomic, strong) MyTableViewController *delegate;
-(void)handleMyAction:(id)sender;
in MyCell.m
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if(action == #selector(handleMyAction:))
{
return YES;
}
return NO;
}
allows the MyCell to be the first responder and response the handleMyAction action by clicking on menu entry.
-(void)handleMyAction:(id)sender
{
[self.delegate handleMyAction:self]; //it's a coincidence both functions have the same name:)
}
this is the definition of the callback function, which will be called when click on the menu entry, and it in turn call the handMyAction function in the delegate of the cell (MyTableViewController, where the logic regarding the cell could be implemented.)
First declare a NSIndexPath type as a class variable.
#property (nonatomic, strong) NSIndexPath *savedIndexPathForThePressedCell;
Now in the Long press gesture recognizer function, get the TableViewCell using the recognizer view. Now save the IndexPath for the TableViewCell
- (void)longPressGestureFunction:(UILongPressGestureRecognizer *)recognizer
{
UITableViewCell *lTableViewCell = (UITableViewCell *)recognizer.view;
[lTableViewCell becomeFirstResponder];
/*Save the Indexpath of the cell pressed*/
self.savedIndexPathForThePressedCell = [mTableView indexPathForCell:lTableViewCell];
if (recognizer.state == UIGestureRecognizerStateBegan)
{
UIMenuItem *MenuDelete = [[UIMenuItem alloc] initWithTitle:#"Delete" action:#selector(Delete:)];
UIMenuItem *MenuForward = [[UIMenuItem alloc] initWithTitle:#"Forward" action:#selector(Forward:)];
UIMenuItem *MenuAddToContacts = [[UIMenuItem alloc] initWithTitle:#"Add To Contacts" action:#selector(addToContacts:)];
mSharedMenu = [UIMenuController sharedMenuController];
[mSharedMenu setMenuItems:[NSArray arrayWithObjects: MenuDelete, MenuForward, nil]];
[mSharedMenu setMenuVisible:YES animated:YES];
}
Now in the Menu selector method, select the row based on the saved indexPath.
- (void)Delete:(id)sender {
// NSLog(#"\n Delete Selected \n");
[mTableView setEditing:YES animated:YES];
[mTableView selectRowAtIndexPath:self.savedIndexPathForThePressedCell animated:YES scrollPosition:UITableViewScrollPositionNone];
}
I hope this helps!!!
I have UITableView to display some list. Implemented UILongPressGestureRecognizer to get calls and on this I want to display menu for delete, upload, etc actions.
Following is implementation
// Registering for long press event
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleLongPress:)];
lpgr.delegate = self;
[self.myTable addGestureRecognizer:lpgr];
On Long Press My control comes to function
- (IBAction)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint p = [gestureRecognizer locationInView:self.playbackTable];
NSIndexPath *indexPath = [self.playbackTable indexPathForRowAtPoint:p];
if (indexPath == nil)
{
NSLog(#"long press on table view but not on a row");
}
else
{
NSLog(#"long press on table view at section %d row %d", indexPath.section, indexPath.row);
CGPoint p = [gestureRecognizer locationInView: self.myTable];
NSIndexPath *indexPath = [self.myTable indexPathForRowAtPoint:p];
if (indexPath != nil)
{
if([self becomeFirstResponder])
{
UIMenuItem *delete = [[UIMenuItem alloc] initWithTitle:#"Delete" action:#selector(deleteFileListItem:)];
menu = [UIMenuController sharedMenuController];
[menu setMenuItems:[NSArray arrayWithObjects:delete, nil]];
[menu setTargetRect:[self.myTable rectForRowAtIndexPath:indexPath] inView:self.myTable];
[menu setMenuVisible:YES animated:YES];
}
}
}
}
}
I have also implemented following methods
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == #selector(deleteFileListItem:))
{
return YES;
}
return NO;
}
-(BOOL)canBecomeFirstResponder
{
return YES;
}
and
- (void)deleteFileListItem:(id)sender
{
// Will perform action here
}
Please let me know if anything is missing or I am doing wrong.
I've been successful when attaching a long press gesture recognizer to each cell, not the entire table view. My guess is that that's the issue here.