IOS UIMenuController UIMenuItem,如何确定使用通用选择器方法选择的项目

Posted

技术标签:

【中文标题】IOS UIMenuController UIMenuItem,如何确定使用通用选择器方法选择的项目【英文标题】:IOS UIMenuController UIMenuItem, how to determine item selected with generic selector method 【发布时间】:2012-02-05 03:26:20 【问题描述】:

使用以下设置

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

如何确定选择了哪个菜单项。

而且不要说你需要有两种方法......提前谢谢。

【问题讨论】:

所以我想没有办法在 ios 中制作“软”菜单? 【参考方案1】:

好的,我已经解决了这个问题。解决方案并不漂亮,更好的选择是“Apple 解决了问题”,但这至少有效。

首先,为您的 UIMenuItem 操作选择器添加前缀“ma​​gic_”。并且不要做出相应的方法。 (如果你能做到,那么你就不需要这个解决方案了)。

我正在构建我的 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];
    

【讨论】:

这是一个支持块的完整实现。 github.com/steipete/PSMenuItem @steipete 你的块实现是天才【参考方案2】:

人们会期望与给定菜单项关联的操作将包含一个sender 参数,该参数应指向所选菜单项。然后,您可以简单地检查项目的标题,或者按照 kforkarim 的建议进行操作并将 UIMenuItem 子类化以包含可用于识别项目的属性。不幸的是,根据this SO question,sender 参数始终为零。这个问题已经有一年多了,所以事情可能已经改变了——看看你在那个参数中得到了什么。

另外,您似乎需要对每个菜单项执行不同的操作。当然,您可以设置它,以便您的所有操作都调用一个通用方法,如果它们都执行非常相似的操作,这可能是有意义的。

【讨论】:

尝试制作软菜单。为此,执行不同的操作是不切实际的。参数并不总是 nil,它是一个菜单。我看不出有什么办法可以按照你所说的去做,所以这个问题,谢谢。【参考方案3】:

如果您继承 UIApplication 并重新实现 -sendAction:to:from:forEvent:,则可以获取代表 UIMenuItem 的 UIButton 对象(实际上是 UICalloutBarButton)。虽然只有-flash选择器通过UIApplication,但已经足够了。

@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(未在旧版本上测试)。

【讨论】:

【参考方案4】:

ort11,您可能想要创建 myuimenuitem 的属性并设置某种标记。这样,发件人的对象可以通过其标签来识别。然后在 Ibaction 中,您可以设置一个 switch 语句,该语句可以对应于每个 sender.tag 并通过该逻辑工作。我想这是最简单的方法。

【讨论】:

发件人是菜单而不是项目。这就是这个问题的原因。 IOS为什么要这么做?从那以后就没有了。 ord11,无论如何,您正在使用不同的“标题”初始化菜单,那么为什么不能按照 Caleb 的建议检查对象的引用及其标题。由于 sender 只是 id 类型,因此您可以检查特定的 Class 类型,然后对照它检查其“标题”。这样您就可以引用 MyUIMenuItem 类类型。像这样的东西。 if ([sender isKindofClass:[MyUIMenuItem class]]) 然后另一个 if 语句 as if ([sender.title isEqualToString:@"Something2"]) then UIMenuController mmi = (UIMenuController) sender;在这种情况下,您的发件人是 *someAction2。希望这会有所帮助 发件人是菜单,而不是菜单项 ort 最初你的发件人是 menuitem,然后你的铸件是菜单。只需在您投射之前获取您的发件人描述的 nslog,以了解发件人对象的概述 发件人是菜单,不是菜单项

以上是关于IOS UIMenuController UIMenuItem,如何确定使用通用选择器方法选择的项目的主要内容,如果未能解决你的问题,请参考以下文章

iOS苹果自带UIMenuController

如何在 iOS 5 中隐藏 UIMenuController

iOS:如何从 UIMenuController 获取选定的 UIMenuItem

iOS 共享 UIMenuController 可能会缓存 UIMenuItem

在 iOS 的 UIMenuController 开头附加自定义 UIMenuItems

如何从 iOS 的 UIMenuController 中删除默认的 UIMenuItem?