I'm using a UIMenuItem
to perform a custom action in UICollectionView
cell long press.
this worked perfectly with iOS 6, but now I am converting my application to iOS 7 and Xcode 5 and it don't work. The custom item do not shown.
UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Unfavorite"
action:@selector(unFavorite:)];
[[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObject:menuItem]];
[UIMenuController sharedMenuController].menuVisible = YES;
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;
{
//do not show default itens like copy, paste....
[self becomeFirstResponder];
return NO;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
// The selector(s) should match your UIMenuItem selector
if (action == @selector(unFavorite:)) {
return YES;
}
return NO;
}
- (void)collectionView:(UICollectionView *)collectionView
performAction:(SEL)action
forItemAtIndexPath:(NSIndexPath *)indexPath
withSender:(id)sender {
}
- (BOOL)collectionView:(UICollectionView *)collectionView
shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath {
myIndexPath = indexPath;
return YES;
}
I don't know about iOS 6, but in iOS 7 it's very simple. You just need the three standard collection view delegate menu-handling methods, plus an action method in the cell subclass. There is no need to play with first responder or anything like that. So, for example (in this example, Copy is a standard item but Capital is something I've added to the menu):
// collection view delegate:
- (BOOL)collectionView:(UICollectionView *)collectionView
shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath {
UIMenuItem* mi = [[UIMenuItem alloc] initWithTitle:@"Capital"
action:NSSelectorFromString(@"capital:")];
[[UIMenuController sharedMenuController] setMenuItems:@[mi]];
return YES;
}
- (BOOL)collectionView:(UICollectionView *)collectionView
canPerformAction:(SEL)action
forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
return (action == NSSelectorFromString(@"copy:") ||
action == NSSelectorFromString(@"capital:"));
}
- (void)collectionView:(UICollectionView *)collectionView
performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath
withSender:(id)sender {
// in real life, would do something here
NSString* state = (self.sectionData)[indexPath.section][indexPath.row];
if (action == NSSelectorFromString(@"copy:"))
NSLog(@"copying %@", state);
else if (action == NSSelectorFromString(@"capital:"))
NSLog(@"fetching the capital of %@", state);
}
// cell subclass:
-(void)capital:(id)sender {
// find my collection view
UIView* v = self;
do {
v = v.superview;
} while (![v isKindOfClass:[UICollectionView class]]);
UICollectionView* cv = (UICollectionView*) v;
// ask it what index path we are
NSIndexPath* ip = [cv indexPathForCell:self];
// talk to its delegate
if (cv.delegate &&
[cv.delegate respondsToSelector:
@selector(collectionView:performAction:forItemAtIndexPath:withSender:)])
[cv.delegate collectionView:cv performAction:_cmd
forItemAtIndexPath:ip withSender:sender];
}
I updated my solution for iOS 7.0 with images and examples in a similar StackOverflow issue.
I use ARC and weak references for the delegate. Seems to work on both iOS 6.0 and iOS 7.0
https://stackoverflow.com/a/13618212/276626
I had added a searchBar on my UICollectionView with the result of the UIMenuController going MIA. After two days trial & error I think finally found a way to make it work.
The Problem (running on iOS7):
I think the trick to make it work is to explicitly remove the first responder status from the searchBar:
- (void)longPressGestureDetected:(UILongPressGestureRecognizer *)gesture {
if(gesture.state == UIGestureRecognizerStateBegan) {
CGPoint touchPoint = [gesture locationInView:gesture.view];
NSInteger index = [self.collectionView indexPathForItemAtPoint:touchPoint].item;
if(index >= 0 && index < self.documents.count) {
// dismiss searchBar
[self.searchBar resignFirstResponder];
[self becomeFirstResponder];
// select the right document
//[self.documentManager selectDocumentWithIndex:index];
// show menu
UIMenuController *menu = [UIMenuController sharedMenuController];
menu.menuItems = [self defaultMenuItems];
[menu setTargetRect:CGRectMake(touchPoint.x, touchPoint.y, 0, 0) inView:gesture.view];
[gesture.view becomeFirstResponder];
[menu update];
[menu setMenuVisible:YES animated:YES];
}
}
of course there are also these responder status methods in the controller:
- (BOOL)canBecomeFirstResponder { return YES; }
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if(action == @selector(renameDocument:)) {
return YES;
} else {
return NO;
}
}
- (NSArray*)defaultMenuItems {
// add menu items
UIMenuItem *renameItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Rename", @"Rename Menu Item") action:@selector(renameDocument:)];
return @[renameItem];
}
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