【问题标题】:UIMenuController not showing upUIMenuController 没有出现
【发布时间】:2010-06-24 18:38:54
【问题描述】:

我正在尝试创建一个自定义 UIMenuController 并将其显示在我的视图中。这是我的代码:

UIMenuController *menuController = [UIMenuController sharedMenuController];
    UIMenuItem *listMenuItem = [[UIMenuItem alloc] initWithTitle:@"List" action:@selector(addList:)];

    [menuController setMenuItems:[NSArray arrayWithObject:listMenuItem]];
    [menuController setTargetRect:CGRectMake(50.0, 50.0, 0, 0) inView:self.view];
    [menuController setMenuVisible:YES animated:YES];

    [listMenuItem release];

没有错误或异常,但菜单控制器没有显示。

【问题讨论】:

    标签: iphone objective-c cocoa-touch ipad uimenucontroller


    【解决方案1】:

    你需要做三件事:

    1. 您需要在视图或视图控制器上调用-becomeFirstResponder
    2. 您的视图或视图控制器需要实现-canBecomeFirstResponder(返回YES)。
    3. (可选)您的视图或视图控制器可以实现 -canPerformAction:action withSender:sender 以单独显示/隐藏菜单项。

    【讨论】:

    • 这在 MonoTouch 中也非常有效——唯一需要注意的是 CanBecomeFirstResponder 是一个属性覆盖,您必须将 UIMenuItem[] 数组分配给 UIMenuController.MenuItems 属性.
    • 当我打电话给becomeFirstResponder 视图时不起作用。在控制器上调用它工作正常。
    • 为了确保对 becomeFirstResponder 的调用成功,您可以检查它返回的 BOOL 是否为 YES。否则你可以期待 UIMenuController 的展示会失败。
    • 只要我实施了第 3 步(非可选),我就可以在 view 上进行这项工作。
    • 实施`-canPerformAction`不是可选的。
    【解决方案2】:

    答案提到了三件事,但要挑剔的话,有六件事:

    1. 菜单处理程序必须是 UIView。如果不是,-becomeFirstResponder 会失败。
    2. 菜单处理程序必须有userInteractionEnabled = YES
    3. 菜单处理程序必须位于视图层次结构中,并且其-window 属性必须与inView: 参数中的视图窗口相同。
    4. 你需要实现-canBecomeFirstResponder并返回YES
    5. 你需要调用[handler becomeFirstResponder]之前[menu setTargetRect:inView:]被调用,否则会失败。
    6. 您需要致电[menu setTargetRect:inView](至少一次)和[menu setMenuVisible:animated:]

    特别是上面的第 1-3 点让我明白了。我想要一个自定义菜单处理程序类,最初是 UIResponder,这导致 -becomeFirstResponder 返回 NO;然后是UIView,但失败了,然后我尝试将其设置为UIButton,但这只是因为userInteractionEnabled 默认为YES 用于按钮,NO 用于UIViews。

    【讨论】:

      【解决方案3】:

      UIMenuController 仅在视图是第一响应者且任何视图上可见

      - (BOOL)canPerformAction 方法返回YES

      因此,如果要在单击按钮时显示菜单控制器,则按钮操作中的第一行应为 [self becomeFirstResponder]。注意:这里 self 是显示菜单的视图。

      如果您的菜单要在长按手势上显示,则在写入之前将 longPressGesture 添加到UIView 和长按事件中

      [menuController setTargetRect:CGRectMake(50.0, 50.0, 0, 0) inView:self.view];
      [menuController setMenuVisible:YES animated:YES];
      

      [self becomeFirstResponder];

      然后按照OZ提到的步骤进行。

      【讨论】:

      • 我试过了,但它不适合我。由于评论有限制,我创建了另一个问题stackoverflow.com/questions/16054050/…
      • 谢谢,targetRect 帮了我大忙。很奇怪,因为我还有另一个几乎相同的类,没有它也能正常工作。
      【解决方案4】:

      下面是一个完整的注释工作示例...

      查看子类头文件

      #import <Foundation/Foundation.h>
      
      @interface MenuControllerSupportingView : UIView
      {
      
      }
      @end
      

      查看子类源文件

      #import "MenuControllerSupportingView.h"
      
      @implementation MenuControllerSupportingView
      
      //It's mandatory and it has to return YES then only u can show menu items..
      -(BOOL)canBecomeFirstResponder
      {
        return YES;
      }
      
      -(void)MenuItemAClicked
      {
        NSLog(@"Menu item A clicked");
      }
      
      -(void)MenuItemBClicked
      {
       NSLog(@"Menu item B clicked");
      }
      
      -(void)MenuItemCClicked
      {
        NSLog(@"Menu item C clicked");
      }
      
      //It's not mandatory for custom menu items
      
      -(BOOL)canPerformAction:(SEL)action withSender:(id)sender
      {  
        if(action == @selector(MenuItemAClicked))
           return YES;
        else if(action == @selector(MenuItemBClicked))
          return YES;
        else if(action == @selector(MenuItemCClicked))
          return YES;
        else
          return NO;
      }
      

      查看控制器头文件

      #import <UIKit/UIKit.h>
      
      @interface ViewController1 : UIViewController
      
      @end
      

      查看控制器源文件

       #import "ViewController1.h"
       #import "MenuControllerSupportingView.h"
      
      @interface ViewController1 ()
      {
       MenuControllerSupportingView *vu;
      }
      @end
      
      @implementation ViewController1
      
       - (void)viewDidLoad
      {
        [super viewDidLoad];
      
        vu=[[SGGI_MenuControllerSupportingView alloc]initWithFrame:CGRectMake(0,0,768,1024)];
      
      [self.view addSubview:vu];
      
       UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
      
       [btn setFrame:CGRectMake(200,200,200,30)];
      
       [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
      
       [btn setTitle:@"Show" forState:UIControlStateNormal];
      
       [btn addTarget:self action:@selector(SHowMenu) forControlEvents:UIControlEventTouchUpInside];
      
       [vu addSubview:btn];
      
      }
      
      -(void)SHowMenu
      {
       UIMenuController *menucontroller=[UIMenuController sharedMenuController];
      
      UIMenuItem *MenuitemA=[[UIMenuItem alloc] initWithTitle:@"A" action:@selector(MenuItemAClicked)];
      
      UIMenuItem *MenuitemB=[[UIMenuItem alloc] initWithTitle:@"B" action:@selector(MenuItemBClicked)];
      
      UIMenuItem *MenuitemC=[[UIMenuItem alloc] initWithTitle:@"C" action:@selector(MenuItemCClicked)];
      
      [menucontroller setMenuItems:[NSArray arrayWithObjects:MenuitemA,MenuitemB,MenuitemC,nil]];
      
          //It's mandatory
      [vu becomeFirstResponder];
      
          //It's also mandatory ...remeber we've added a mehod on view class
      if([vu canBecomeFirstResponder])
      {
      
          [menucontroller setTargetRect:CGRectMake(10,10, 0, 200) inView:vu];
      
          [menucontroller setMenuVisible:YES animated:YES];
      }
      
      }
      
      
      
      
      -(void)didReceiveMemoryWarning
      {
        [super didReceiveMemoryWarning];
      
      }
      
      @end
      

      在 View 类中,如果你在 canPerformAction 中单独编写 return YES,你将看到所有默认菜单项,如相机符号、剪切、复制等。

      -(BOOL)canPerformAction:(SEL)action withSender:(id)sender
      {
       return YES;
      }
      

      如果你想单独展示像相机这样的东西

      -(BOOL)canPerformAction:(SEL)action withSender:(id)sender
      {
      if(action==@selector(_insertImage:))
           return YES;
      else
           return NO;
      
      }
      

      如果你想知道所有的动作然后

      访问link

      【讨论】:

      • 非常有帮助,我在 swift 中添加了类似的代码来子类化 UIButton,并且像魔术一样工作。谢谢。
      【解决方案5】:

      以防万一任何人在 iOS6 中特别(随机)遇到此问题:您可能想查看与在设备上启用“朗读选择”相关的this SO(设置 -> 常规 -> 辅助功能 -> 朗读选择:在)。我的少数用户无法看到自定义 UIMenuItems,这就是原因。

      【讨论】:

        【解决方案6】:

        在 Swift 3.0 中 -

        在我的例子中,我想让 VC 预先选择 TextView 中的文本,并显示一个自定义菜单供用户对该选择执行操作。正如 Kalle 所提到的,顺序非常重要,尤其是将setMenuVisible 放在最后。

        在 VC 中,viewDidLoad:

        menuCont = UIMenuController.shared
        let menuItem1: UIMenuItem = UIMenuItem(title: "Text", action: #selector(rtfView.textItem(_:)))
        let menuItems: NSArray = [menuItem1]
        menuCont.menuItems = menuItems as? [UIMenuItem]
        

        在 VC 中,当用户点击按钮时:

        @IBAction func pressed(_ sender: Any) {
            self.textView.selectedRange = NSMakeRange(rangeStart, rangeLength)
            self.textView.becomeFirstResponder()
            menuCont.setTargetRect(CGRect.zero, in: self.textView)
            menuCont.setMenuVisible(true, animated: true)
        }
        

        最后,在TextView的子类中:

        class rtfView: UITextView {
        
        override var canBecomeFirstResponder: Bool {
            return true
        }
        
        override func canPerformAction(_ action: Selector, withSender sender: Any!) -> Bool {
            if (action == #selector(textItem(_:))) {
                return true
            } else {
                return false
            }
          }
        }
        

        【讨论】:

          【解决方案7】:

          可能是因为CGRectMake(50.0, 50.0, 0, 0)width = 0height = 0 创建了一个CGRect

          干杯, 安卡

          【讨论】:

          • 即使我将宽度/高度设置为 100 之类的值,仍然不显示。
          • 好的,你可以尝试添加方法(BOOL)canPerformAction:(SEL)action withSender:(id)sender 并返回YES。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-12-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-24
          • 1970-01-01
          • 2018-07-22
          相关资源
          最近更新 更多