Unable to get UIMenuController to display custom elements

So, I'm not sure if something is wrong here, but I have a UIViewController that has a UICollectionView on it. In the UIViewController viewDidLoad method, I do the following: it does not add any custom menu items to the popup that appears.

 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 set collectionView:shouldShowMenuForItemAtIndexPath: and collectionView:canPerformAction:forItemAtIndexPath:withSender: to return YES under any circumstances, but regardless of whether only Cut, Copy, and Paste are displayed.

Didn't I implement it fully or did it right? Thanks, in extended, for any help that can be provided.

PS - I looked at as many examples as I could, all over Google, and I did not find anything that helped.

+4
source share
3 answers

You're right. It is not possible to customize the menu that appears when you long click on a table view cell or collection.

I discuss the problem in my book:

http://www.apeth.com/iOSBook/ch21.html#_table_view_menus

As I said, copying, cutting and pasting is the only choice you have. You will need to make the menu come from something else if you want to customize it.

EDIT: In the version of my iOS 7 book, I demonstrate a way to do this. This is the same for table cells and collection cells, so I will start by solving the table cell. The trick is that you must implement the action method in a subclass of the cell. 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

This is the only tricky part. Then, in the controller class, you do for abbrev: what you do for any menu. In shouldShowMenuForRowAtIndexPath: add it to the custom menu. Then do canPerformAction: and performAction: just as you would expect (scroll to the end):

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p454tableCellMenus2/ch21p718sections/RootViewController.m

Here's a parallel implementation for collection cells: cell subclass:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p466collectionViewFlowLayout2/ch21p748collectionViewFlowLayout2/Cell.m

And the controller (scroll to the end):

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p466collectionViewFlowLayout2/ch21p748collectionViewFlowLayout2/ViewController.m

These approaches are also translated into Swift (not without much difficulty) in the iOS 8 version of my book.

+3
source

I managed to implement custom menus in UICollectionViewCell by following the instructions on this link ( fooobar.com/questions/679503 / ... ) using improvisation.

In my UICollectionViewController, I have implemented custom menu items by adding them to the menu controller, as in a link.

Then I did the following in a 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 similarly 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 should be the same as implemented in the collection controller.

If you want to enable copy or paste functions, add them to canPerformAction: and then change the collectionView :: canPerformAction: command to return YES.

This may not be the best way to do this, but it worked for me.

+6
source

Step 1: Creating 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 the menu controller

 mc.menuItems = [NSArray arrayWithObjects: miCustom1, miCustom2, nil]; 

Step 4. Creating action methods for items

 - (void) onCustom1: (UIMenuController*) sender { } - (void) onCustom2: (UIMenuController*) sender { } 

Step 5: its optional to install 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 off your MenuController for some buttons.

 UIMenuController* mc = [UIMenuController sharedMenuController]; CGRect bounds = sender.view.bounds; [mc setTargetRect: sender.view.frame inView:sender.view.superview]; [mc setMenuVisible:YES animated: YES]; 
+1
source

All Articles