IOS UIMenuController UIMenuItem, как определить элемент, выбранный с помощью универсального метода выбора - PullRequest
7 голосов
/ 05 февраля 2012

Со следующей настройкой

....
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;
}

Как выяснить, какой пункт меню был выбран.

И не говорите, что вам нужно использовать два метода ... Заранее спасибо.

Ответы [ 4 ]

15 голосов
/ 26 марта 2012

Хорошо, я решил это. Решение не изящное, и лучший вариант - «Apple решает проблему», но это, по крайней мере, работает.

Прежде всего, префикс ваших UIMenuItem селекторов действий с " magic_ ". И не делайте соответствующие методы. (Если вы можете сделать это, то вам все равно не нужно это решение).

Я создаю свои UIMenuItems таким образом:

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;

Теперь вашему классу, который ловит сообщения о нажатиях кнопок, нужно несколько дополнений. (В моем случае класс является подклассом UITextField . Ваш может быть чем-то другим.)

Прежде всего, метод, который мы все хотели иметь, но которого не было:

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

Тогда методы, которые делают это возможным:

- (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];
    }
}
0 голосов
/ 18 сентября 2013

Оказывается, можно получить объект UIButton (который на самом деле является UICalloutBarButton), который представляет UIMenuItem, если вы подкласс UIApplication и переопределите -sendAction:to:from:forEvent:. Хотя только UICpplication проходит через -flash, этого достаточно.

@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

Вы можете сохранить target (или любые нужные вам данные), например, в. собственности и доступ к нему позже от действия вашего UIMenuItem.

И чтобы ваш подкласс UIApplication работал, вы должны передать его имя в качестве третьего параметра UIApplicationMain():

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

Это решение работает на iOS 5.x-7.0 на дату публикации (не тестировалось на старых версиях).

0 голосов
/ 05 февраля 2012

Можно ожидать, что действие, связанное с данным элементом меню, будет включать параметр sender, который должен указывать на выбранный элемент меню.Затем вы можете просто проверить название элемента или сделать так, как предлагает kforkarim, и создать подкласс UIMenuItem, чтобы включить свойство, которое вы можете использовать для идентификации элемента.К сожалению, согласно этому вопросу SO , параметр отправителя всегда равен нулю.Этому вопросу больше года, поэтому все может измениться - взгляните, что вы получаете в этом параметре.

С другой стороны, похоже, что для каждого пункта меню вам понадобится другое действие.Конечно, вы можете настроить его так, чтобы все ваши действия вызывали общий метод, и если они все делают что-то очень похожее, это может иметь смысл.

0 голосов
/ 05 февраля 2012

ort11, вы можете создать свойство myuimenuitem и установить какой-нибудь тег. Таким образом, объект отправителя может быть распознан по его тегу. В Ibaction вы можете установить оператор switch, который может соответствовать каждому sender.tag, и работать с этой логикой. Я думаю, это самый простой способ.

...