在选择文本时,如何用自己的视图替换UIMenuController?

时间:2013-01-30 02:16:02

标签: iphone ios objective-c ipad uimenucontroller

当选择文本时,默认情况下会弹出UIMenuController,其中包含剪切/复制/粘贴等。

enter image description here

我想用我自己的自定义视图替换它(看起来相似,但是高两倍,以便我可以有两行按钮/自定义视图)。我怎么能这样做?

我知道没有简单的方法。我期待如果有一个简单的解决方案,它将不会非常优雅。代码也不能使用任何私有API。

我真的,真的不必实现我自己的文本视图,重新实现文本选择和输入,并重新实现放大视图,这样我就可以编写自己的UIMenuController克隆,如果有任何方法可以避免它。应用程序的界面非常重要,我可以替换UIMenuController,所以如果没有其他答案,那么我可能最终会这样做。如果有人能为我节省大量时间并提出另一种更简单的方法,我将非常感激!

2 个答案:

答案 0 :(得分:31)

在开始之前,您必须了解三件重要事项:

1)您必须编写自定义菜单控制器视图,但我想您有点期待。我只知道自定义菜单控制器的commercial实现,但这不应该太难。

2) UIResponder上有一个名为-canPerformAction:withSender:的有用方法。在UIResponder Class Reference中了解有关它的更多信息。您可以使用该方法确定文本视图是否支持特定的标准操作(在UIResponderStandardEditActions协议中定义) 在决定在自定义菜单控制器中显示哪些项目时,这将非常有用。例如,只有当用户的粘贴板包含要粘贴的字符串时,才会显示“粘贴”菜单项。

3)您可以通过收听UIMenuController通知来检测何时显示UIMenuControllerWillShowMenuNotification

现在你已经了解了所有这些,这就是我开始解决这个问题的方法:

1)在文本视图为第一响应者时监听UIMenuControllerWillShowMenuNotification

- (void)textViewDidBeginEditing:(UITextView *)textView {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuWillBeShown:) name:UIMenuControllerWillShowMenuNotification object:nil];
}

- (void)textViewDidEndEditing:(UITextView *)textView {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillShowMenuNotification object:nil];
}

2)显示您的自定义菜单控制器,而不是默认的UIMenuController

- (void)menuWillBeShown:(NSNotification *)notification {
    CGRect menuFrame = [[UIMenuController sharedMenuController] menuFrame];
    [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO]; // Don't show the default menu controller

    CustomMenuController *controller = ...;
    controller.menuItems = ...;
    // additional stuff goes here

    [controller setTargetRectWithMenuFrame:menuFrame]; // menuFrame is in screen coordinates, so you might have to convert it to your menu's presenting view/window/whatever

    [controller setMenuVisible:YES animated:YES];
}

<强>混杂。 1)您可以使用全屏UIWindow来显示自定义菜单,以便它可以与状态栏重叠。

UIWindow *presentingWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
presentingWindow.windowLevel = UIWindowLevelStatusBar + 1;
presentingWindow.backgroundColor = [UIColor clearColor];

[presentingWindow addSubview:controller];
[presentingWindow makeKeyAndVisible];

<强>混杂。 2)要确定显示哪些菜单项,可以使用上述-canPerformAction:withSender:

BOOL canPaste = [textView canPerformAction:@selector(paste:) withSender:nil];
BOOL canSelectAll = [textView canPerformAction:@selector(selectAll:) withSender:nil];

<强>混杂。 3)你必须在演示窗口或类似的东西上使用UITapGestureRecognizer来自行解雇菜单。

这并不容易,但它是可行的,我希望它能很好地适合你。祝你好运!

<强>更新
今天在cocoacontrols.com上弹出了一个新菜单实现,您可能想要查看:https://github.com/questbeat/QBPopupMenu

更新2:
this answer中所述,您可以使用-caretRectForPosition:获取文本视图所选文本的框架。

答案 1 :(得分:3)

我认为这可能对您有所帮助https://github.com/cxa/UIMenuItem-CXAImageSupport

UIMenuItem使用UILabel显示其标题,这意味着我们可以调用-drawTextInRect:来支持图像。

UIMenuItem + CXAImageSupport是一个肮脏的黑客,但在大多数情况下应该是安全的。不包含任何私有API。

为UIMenuItem创建一个类别而不是子类,可以获得更大的灵活性。是的,这个类别也可以应用于很棒的PSMenuItem!

enter image description here