IOS UIMenuController UIMenuItem how to determine an item selected using a universal selection method

Next time setup

.... MyUIMenuItem *someAction = [[MyUIMenuItem alloc]initWithTitle : @"Something" action : @selector(menuItemSelected:)]; MyUIMenuItem *someAction2 = [[MyUIMenuItem alloc]initWithTitle : @"Something2" action : @selector(menuItemSelected:)]; .... - (IBAction) menuItemSelected : (id) sender { UIMenuController *mmi = (UIMenuController*) sender; } 

How to determine which menu item was selected.

And don't say you need to have two methods ... Thanks in advance.

+6
source share
4 answers

Ok, I solved it. The solution is not very pretty, and the best option is β€œApple fixes the problem,” but at least it works.

First of all, the UIMenuItem action selector prefix with the magic _ parameter. And do not do the appropriate methods. (If you can do this, then you still do not need this solution).

I build my UIMenuItems in this way:

 NSArray *buttons = [NSArray arrayWithObjects:@"some", @"random", @"stuff", nil]; NSMutableArray *menuItems = [NSMutableArray array]; for (NSString *buttonText in buttons) { NSString *sel = [NSString stringWithFormat:@"magic_%@", buttonText]; [menuItems addObject:[[UIMenuItem alloc] initWithTitle:buttonText action:NSSelectorFromString(sel)]]; } [UIMenuController sharedMenuController].menuItems = menuItems; 

Now your class that catches button click messages needs a few additions. (In my case, the class is a subclass of UITextField . Maybe it could be something else.)

First, the method that we all wanted to have, but which was not:

 - (void)tappedMenuItem:(NSString *)buttonText { NSLog(@"They tapped '%@'", buttonText); } 

Then methods that allow you to:

 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { NSString *sel = NSStringFromSelector(action); NSRange match = [sel rangeOfString:@"magic_"]; if (match.location == 0) { return YES; } return NO; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { if ([super methodSignatureForSelector:sel]) { return [super methodSignatureForSelector:sel]; } return [super methodSignatureForSelector:@selector(tappedMenuItem:)]; } - (void)forwardInvocation:(NSInvocation *)invocation { NSString *sel = NSStringFromSelector([invocation selector]); NSRange match = [sel rangeOfString:@"magic_"]; if (match.location == 0) { [self tappedMenuItem:[sel substringFromIndex:6]]; } else { [super forwardInvocation:invocation]; } } 
+14
source

One would expect that the action associated with this menu item would include the sender parameter, which should point to the selected menu item. Then you can simply examine the element's title or have kforkarim suggest and subclass UIMenuItem to include proeprty, which you can use to identify the element. Unfortunately, according to this SO question , the sender parameter is always zero. This question is older than a year, so everything can change - take a look at what you get with this parameter.

Alternatively, it looks like for each menu item you need a different action. Of course, you can configure it so that all your actions invoke a common method, and if they all do something very similar, that might make sense.

0
source

It turns out you can get a UIButton object (which is actually UICalloutBarButton) that represents UIMenuItem if you subclass UIApplication and override -sendAction:to:from:forEvent: Although only the -flash selector passes through UIApplication, that’s enough.

 @interface MyApplication : UIApplication @end @implementation MyApplication - (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event { // target == sender condition is just an additional one if (action == @selector(flash) && target == sender && [target isKindOfClass:NSClassFromString(@"UICalloutBarButton")]) { NSLog(@"pressed menu item title: %@", [(UIButton *)target titleLabel].text); } return [super sendAction:action to:target from:sender forEvent:event]; } @end 

You can save target (or whatever data you need from it), for example. property and access to it later from your UIMenuItem action.

And for your UIApplication subclass to work, you must pass its name as the third parameter to UIApplicationMain() :

 int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([YOUR_APP_DELEGATE class])); } } 

This solution works on iOS 5.x-7.0 from the date of publication (not tested in older versions).

0
source

ort11, you can create the myuimenuitem property and set some tag. How the sender object can be recognized by its tag. In Ibaction, you can set a switch statement that can match each sender.tag and work with this logic. I think this is the easiest way.

-1
source

Source: https://habr.com/ru/post/905298/


All Articles