22

选择文本时,默认情况下,uimenucontroller会弹出剪切/复制/粘贴等。

在此处输入图像描述

我想用我自己的自定义视图替换它(外观相似,但高一倍,以便我可以有两行按钮/自定义视图)。我怎样才能做到这一点?

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

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

4

2 回答 2

32

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

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

2)UIResponder被调用有一个有用的方法-canPerformAction:withSender:在UIResponder 类参考中阅读更多关于它的信息。您可以使用该方法来确定您的文本视图是否支持特定的标准操作(在UIResponderStandardEditActions协议中定义)。
这在决定在自定义菜单控制器中显示哪些项目时很有用。例如,仅当用户的粘贴板包含要粘贴的字符串时,才会显示粘贴菜单项。

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

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

1)UIMenuControllerWillShowMenuNotification当文本视图是第一响应者时监听s

- (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在呈现窗口上使用 a 或类似的东西自己处理关闭菜单。

这并不容易,但它是可行的,我希望它对你很有效。祝你好运!

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

更新 2:
本答案中所述,您可以使用-caretRectForPosition:.

于 2013-02-05T16:18:57.633 回答
3

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

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

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

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

在此处输入图像描述

于 2013-01-30T02:46:01.500 回答