So, I am not sure if I am doing something wrong here, but I have a UIViewController that has a UICollectionView on it. In the UIViewController's viewDidLoad
method, I do the following it doesn't add any custom menu items to the popup that shows up.
UIMenuItem *removeItem = [[UIMenuItem alloc] initWithTitle:@"Remove" action:@selector(handleRemoveItem:)];
UIMenuItem *duplicateItem = [[UIMenuItem alloc] initWithTitle:@"Duplicate" action:@selector(handleDuplicateItem:)];
[[UIMenuController sharedMenuController] setMenuItems:@[removeItem, duplicateItem]];
[removeItem release];
[duplicateItem release];
I did set the collectionView:shouldShowMenuForItemAtIndexPath:
and the collectionView:canPerformAction:forItemAtIndexPath:withSender:
to return YES
under all circumstances, but no matter what, only Cut, Copy, and Paste will show up.
Did I not implement this fully, or did I not do it right?
P.S. - I did look at as many examples as I could throughout google and I didn't find anything that helped.
I was able to implement custom menus on a UICollectionViewCell by following the instructions on this link (https://stackoverflow.com/a/13618212/2313416) with some improvising.
In my UICollectionViewController, I implemented the custom menu items by adding them to the menu controller as in the link.
I then implemented the following in the UICollectionViewController:
- (BOOL)collectionView:(UICollectionView *)cv canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
return NO;
}
- (BOOL)collectionView:(UICollectionView *)cv shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)collectionView:(UICollectionView *)cv performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
NSLog(@"perform action:%@", NSStringFromSelector(action));
}
In my UICollectionViewCell, I implemented similar to the following:
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == @selector(onCustom1:)) {
return YES;
}
if (action == @selector(onCustom2:)) {
return YES;
}
return NO;
}
These actions have to be the same as implemented in the Collection Controller.
If one wants to include the copy or paste functions, add them to the canPerformAction: and then change the collectionView::canPerformAction: to return YES.
This may not be the best way of doing it, but has worked for me.
You are correct. It is impossible to customize the menu that appears when you do a long press on a table view cell or collection view cell.
I discuss the problem in my book:
http://www.apeth.com/iOSBook/ch21.html#_table_view_menus
As I say there, Copy, Cut and Paste are the only choices you can have. You will have to make the menu emanate from something else if you want to customize it.
EDIT: In the iOS 7 version of my book, I demonstrate a way to do this. It's the same for table view cells and collection view cells, so I'll start with the table view cell solution. The trick is that you must implement the action method in a cell subclass. For example, if your custom action selector is abbrev:
, you must subclass the cell and implement abbrev:
:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p454tableCellMenus2/ch21p718sections/MyCell.m
That's the only tricky part. Then, back in your controller class, you do for abbrev:
exactly what you would do for any menu. In shouldShowMenuForRowAtIndexPath:
, add it to the custom menu. Then implement canPerformAction:
and performAction:
just as you would expect (scroll all the way to the bottom):
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p454tableCellMenus2/ch21p718sections/RootViewController.m
Here's the parallel implementation for collection view cells: the cell subclass:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p466collectionViewFlowLayout2/ch21p748collectionViewFlowLayout2/Cell.m
And the controller (scroll all the way to the bottom):
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p466collectionViewFlowLayout2/ch21p748collectionViewFlowLayout2/ViewController.m
Those approaches are also translated into Swift (not without some difficulty) in the iOS 8 edition of my book.
Step 1 : Create Menu Items
UIMenuItem* miCustom1 = [[UIMenuItem alloc] initWithTitle:@"Custom 1" action:@selector(onCustom1:)];
UIMenuItem* miCustom2 = [[UIMenuItem alloc] initWithTitle: @"Custom 2" action:@selector(onCustom2:)];
Step 2: Create MenuController
UIMenuController* mc = [UIMenuController sharedMenuController];
Step 3 : Add Items to Menu Controller
mc.menuItems = [NSArray arrayWithObjects: miCustom1, miCustom2, nil];
Step 4 : Create Action Methods for Items
- (void) onCustom1: (UIMenuController*) sender
{
}
- (void) onCustom2: (UIMenuController*) sender
{
}
Step 5 : its optionally to set FirstResponder for Actions
- (BOOL) canPerformAction:(SEL)action withSender:(id)sender
{
if ( action == @selector( onCustom1: ) )
{
return YES; // logic here for context menu show/hide
}
if ( action == @selector( onCustom2: ) )
{
return NO; // logic here for context menu show/hide
}
if ( action == @selector( copy: ) )
{
// turn off copy: if you like:
return NO;
}
return [super canPerformAction: action withSender: sender];
}
Step 6 : Finally Show your MenuController on Some Button Action
UIMenuController* mc = [UIMenuController sharedMenuController];
CGRect bounds = sender.view.bounds;
[mc setTargetRect: sender.view.frame inView:sender.view.superview];
[mc setMenuVisible:YES animated: YES];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With