67

我正在尝试创建一个自定义 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];

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

4

7 回答 7

177

你需要做三件事:

  1. 您需要调用-becomeFirstResponder视图或视图控制器。
  2. 您的视图或视图控制器需要实现-canBecomeFirstResponder(返回YES)。
  3. 或者,您的视图或视图控制器可以实现-canPerformAction:action withSender:sender单独显示/隐藏菜单项。
于 2010-09-09T04:32:29.930 回答
23

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

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

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

于 2014-05-23T22:37:19.830 回答
15

UIMenuController只有当视图是第一响应者并且

- (BOOL)canPerformAction方法返回YES

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

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

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

[self becomeFirstResponder];

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

于 2010-12-27T08:51:44.070 回答
7

下面是一个完整的评论工作示例...

查看子类头文件

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

}

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

访问链接

于 2013-08-09T12:28:17.263 回答
2

以防万一有人在 iOS6 上特别(随机)遇到这个问题:您可能想查看与在设备上启用 Speak Selection 相关的SO (设置 -> 常规 -> 辅助功能 -> Speak Selection: On)。我的少数用户无法看到自定义UIMenuItems,这就是原因。

于 2012-12-24T23:03:07.203 回答
1

在 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
    }
  }
}
于 2017-03-14T10:36:00.083 回答
-1

也许是因为CGRectMake(50.0, 50.0, 0, 0)创建了一个CGRectwith width = 0and height = 0

干杯,安卡

于 2010-06-24T18:50:24.800 回答