【问题标题】:Can't get UIMenuController to show custom items无法让 UIMenuController 显示自定义项目
【发布时间】:2013-04-03 02:44:52
【问题描述】:

所以,我不确定我是否在这里做错了,但我有一个 UIViewController 上面有一个 UICollectionView。在 UIViewController 的 viewDidLoad 方法中,我执行以下操作,它不会将任何自定义菜单项添加到显示的弹出窗口中。

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

我确实将collectionView:shouldShowMenuForItemAtIndexPath:collectionView:canPerformAction:forItemAtIndexPath:withSender: 设置为在所有情况下都返回YES,但无论如何,只会显示剪切、复制和粘贴。

我没有完全实现这一点,还是我做得不对?

附: - 我确实在整个 google 中查看了尽可能多的示例,但没有发现任何帮助。

【问题讨论】:

    标签: objective-c uicollectionview uimenucontroller uimenuitem


    【解决方案1】:

    按照此链接 (https://stackoverflow.com/a/13618212/2313416) 上的说明进行一些即兴创作,我能够在 UICollectionViewCell 上实现自定义菜单。

    在我的 UICollectionViewController 中,我通过将自定义菜单项添加到链接中的菜单控制器来实现它们。

    然后我在 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));
    }
    

    在我的 UICollectionViewCell 中,我实现了类似于以下内容:

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

    这些操作必须与集合控制器中实现的相同。

    如果想要包含复制或粘贴功能,请将它们添加到 canPerformAction: 中,然后将 collectionView::canPerformAction: 更改为返回 YES。

    这可能不是最好的方法,但对我有用。

    【讨论】:

    • 这会导致崩溃,因为它找不到 onCustom1: 你是如何将它路由到 collectionView 的?
    • @RyanPoolos 在 CollectionViewController viewDidLoad 中,我创建了一个自定义 UIMenuItems 对象的 NSArray。对于他们的行为,我输入了“@action(onCustom1:)”和“@action(onCustom2:)”。在 UICollectionViewCell 头文件中,我声明了“-(void)onCustom1:(id)sender”和“-(void)onCustom2:(id)sender”。然后将这些方法放入我的 UICollectionViewCell.m 文件中。
    • 哦,好的。我以为你已经找到了一种在单元格和集合之间架起桥梁的方法。
    • 将它添加到 collectionView 单元格就像一个魅力。这以前在 ios6 paulsolt.com/2012/11/… 中有效,但在 ios7 中停止了,所以根据您的提示,我的应用程序再次运行!
    【解决方案2】:

    你是对的。无法自定义长按表格视图单元格或集合视图单元格时出现的菜单。

    我在书中讨论了这个问题:

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

    正如我所说,复制、剪切和粘贴是您唯一的选择。如果要自定义菜单,则必须使菜单源自其他内容。

    编辑:在我的书的 iOS 7 版本中,我演示了一种方法来做到这一点。表格视图单元格和集合视图单元格也是如此,所以我将从表格视图单元格解决方案开始。诀窍是您必须在单元子类中实现操作方法。例如,如果您的自定义操作选择器是abbrev:,您必须子类化单元格并实现abbrev:

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

    这是唯一棘手的部分。然后,回到你的控制器类,你为abbrev: 做的正是你对任何菜单所做的。在shouldShowMenuForRowAtIndexPath: 中,将其添加到自定义菜单。然后按照您的预期实现canPerformAction:performAction:(一直滚动到底部):

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

    这里是集合视图单元格的并行实现:单元格子类:

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

    和控制器(一直滚动到底部):

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

    这些方法在我的 iOS 8 版本中也被翻译成 Swift(并非没有困难)。

    【讨论】:

    • 是的,我有那种感觉,所以我改变了使用它的方式,暂时显示UIActionSheet。一旦我有机会制作自己的收藏视图,那么我可能会实现它。谢谢!
    • 还请向 Apple 提交错误。这是一个非常愚蠢的限制。
    • 如果你这样做,它会工作,paulsolt.com/2012/11/… 很好,它在 ios6 中也是如此
    • 好吧,我认为你可以做到。这是一种方法:UIMenuItem *duplicateMenuItem = [[UIMenuItem alloc] initWithTitle:@"duplicate"] action:@selector(duplicate:)]; _menuController.menuItems = [NSArray arrayWithObjects:duplicateMenuItem,nil]; 当然,您必须定义选择器:- (void)duplicate:(id)sender { // do your stuff; }
    • @Sourabh 我最终确实找到了一种方法。我会修改我的答案来描述它。
    【解决方案3】:

    第 1 步:创建菜单项

    UIMenuItem* miCustom1 = [[UIMenuItem alloc] initWithTitle:@"Custom 1" action:@selector(onCustom1:)];
    UIMenuItem* miCustom2 = [[UIMenuItem alloc] initWithTitle: @"Custom 2" action:@selector(onCustom2:)];
    

    第 2 步:创建 MenuController

    UIMenuController* mc = [UIMenuController sharedMenuController];
    

    第 3 步:向菜单控制器添加项目

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

    第 4 步:为项目创建操作方法

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

    第 5 步:可以选择为操作设置 FirstResponder

    - (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];
    }
    

    第 6 步:最后在某些按钮操作上显示您的 MenuController

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

    【讨论】:

    • 不幸的是,这似乎不适用于 UICollectionView 类。
    • @AndrewRiebe 你找到 UICollectionView 类的解决方案了吗?
    猜你喜欢
    • 1970-01-01
    • 2018-10-11
    • 2018-05-02
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 1970-01-01
    • 2013-06-06
    相关资源
    最近更新 更多