如何真正从 UIMenuController 中删除 Copy

发布于 2024-11-18 23:33:34 字数 2874 浏览 3 评论 0原文

显然曾经有一个简单的方法 以防止当您添加多个自定义菜单项时 UIMenuController 中出现“更多...”标签。您只需删除所有系统菜单项即可。甚至还有一个解决方法仍然可以进行复制工作。您只需使用不同的选择器实现自定义复制命令,然后覆盖 canPerformAction:withSender: 即可不显示系统副本:

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{
    if (action == @selector(copy:))
       return NO;
    else
       // logic to show or hide other things
}

不幸的是,此方法不再有效(至少在 UIWebView 子类中)。除了 copy: 之外,每个系统菜单项都会调用 canPerformAction:withSender: ,因此结果是系统复制菜单项始终显示。这意味着,如果您有多个自定义菜单项,它们总是隐藏在“更多...”后面。

因此,有没有一种方法可以真正删除系统的复制项或某种替代方法来防止菜单项隐藏在“更多... ”后面……”?

更新

这是我重写 canPerformAction:withSender 时得到的输出:请注意,永远不会为“copy:”操作调用该方法:

cannot perform action cut: with sender <UIMenuController: 0x7227d30>.
cannot perform action select: with sender <UIMenuController: 0x7227d30>.
cannot perform action selectAll: with sender <UIMenuController: 0x7227d30>.
cannot perform action paste: with sender <UIMenuController: 0x7227d30>.
cannot perform action delete: with sender <UIMenuController: 0x7227d30>.
cannot perform action promptForReplace: with sender <UIMenuController: 0x7227d30>.
cannot perform action _showMoreItems: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setRtoLTextDirection: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setLtoRTextDirection: with sender <UIMenuController: 0x7227d30>.
can perform action customCopy: with sender <UIMenuController: 0x7227d30>.
can perform action custom1: with sender <UIMenuController: 0x7227d30>.
cannot perform action custom2: with sender <UIMenuController: 0x7227d30>.
can perform action custom3: with sender <UIMenuController: 0x7227d30>.
can perform action custom4: with sender <UIMenuController: 0x7227d30>.
cannot perform action cut: with sender <UIMenuController: 0x7227d30>.
cannot perform action select: with sender <UIMenuController: 0x7227d30>.
cannot perform action selectAll: with sender <UIMenuController: 0x7227d30>.
cannot perform action paste: with sender <UIMenuController: 0x7227d30>.
cannot perform action delete: with sender <UIMenuController: 0x7227d30>.
cannot perform action promptForReplace: with sender <UIMenuController: 0x7227d30>.
cannot perform action _showMoreItems: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setRtoLTextDirection: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setLtoRTextDirection: with sender <UIMenuController: 0x7227d30>.

There apparently used to be an easy way to prevent the "More..." label from appearing in UIMenuController when you added more than one custom menu item. You just had to remove all of the system menu items. There was even a workaround here for still having copy work. You just had to implement a custom copy command using a different selector and then override canPerformAction:withSender: to not show the system copy:

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{
    if (action == @selector(copy:))
       return NO;
    else
       // logic to show or hide other things
}

Unfortunately this method no longer works (at least in a UIWebView subclass). canPerformAction:withSender: is called for every system menu item except copy: so the result is that the system copy menu item is always displayed. This means that if you have more than one custom menu item, they are always hidden behind "More..."

So, is there a way to really remove the system's copy item or some alternate way to prevent menu items from hiding behind "More..."?

Update

This is the output I get when I override canPerformAction:withSender: notice that the method is never called for the "copy:" action:

cannot perform action cut: with sender <UIMenuController: 0x7227d30>.
cannot perform action select: with sender <UIMenuController: 0x7227d30>.
cannot perform action selectAll: with sender <UIMenuController: 0x7227d30>.
cannot perform action paste: with sender <UIMenuController: 0x7227d30>.
cannot perform action delete: with sender <UIMenuController: 0x7227d30>.
cannot perform action promptForReplace: with sender <UIMenuController: 0x7227d30>.
cannot perform action _showMoreItems: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setRtoLTextDirection: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setLtoRTextDirection: with sender <UIMenuController: 0x7227d30>.
can perform action customCopy: with sender <UIMenuController: 0x7227d30>.
can perform action custom1: with sender <UIMenuController: 0x7227d30>.
cannot perform action custom2: with sender <UIMenuController: 0x7227d30>.
can perform action custom3: with sender <UIMenuController: 0x7227d30>.
can perform action custom4: with sender <UIMenuController: 0x7227d30>.
cannot perform action cut: with sender <UIMenuController: 0x7227d30>.
cannot perform action select: with sender <UIMenuController: 0x7227d30>.
cannot perform action selectAll: with sender <UIMenuController: 0x7227d30>.
cannot perform action paste: with sender <UIMenuController: 0x7227d30>.
cannot perform action delete: with sender <UIMenuController: 0x7227d30>.
cannot perform action promptForReplace: with sender <UIMenuController: 0x7227d30>.
cannot perform action _showMoreItems: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setRtoLTextDirection: with sender <UIMenuController: 0x7227d30>.
cannot perform action _setLtoRTextDirection: with sender <UIMenuController: 0x7227d30>.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

小忆控 2024-11-25 23:33:34

您链接到的技术似乎仍然有效。我用这些方法实现了 UIWebView 子类,并且只出现了 A 和 B 项。

+ (void)initialize
{
    UIMenuItem *itemA = [[UIMenuItem alloc] initWithTitle:@"A" action:@selector(a:)];
    UIMenuItem *itemB = [[UIMenuItem alloc] initWithTitle:@"B" action:@selector(b:)];
    [[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObjects:itemA, itemB, nil]];
    [itemA release];
    [itemB release];
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    BOOL can = [super canPerformAction:action withSender:sender];
    if (action == @selector(a:) || action == @selector(b:))
    {
        can = YES;
    }
    if (action == @selector(copy:))
    {
        can = NO;
    }
    NSLog(@"%@ perform action %@ with sender %@.", can ? @"can" : @"cannot", NSStringFromSelector(action), sender);
    return can;
}

The technique you linked to still seems to work. I implemented a UIWebView subclass with these methods, and only the A and B items appeared.

+ (void)initialize
{
    UIMenuItem *itemA = [[UIMenuItem alloc] initWithTitle:@"A" action:@selector(a:)];
    UIMenuItem *itemB = [[UIMenuItem alloc] initWithTitle:@"B" action:@selector(b:)];
    [[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObjects:itemA, itemB, nil]];
    [itemA release];
    [itemB release];
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    BOOL can = [super canPerformAction:action withSender:sender];
    if (action == @selector(a:) || action == @selector(b:))
    {
        can = YES;
    }
    if (action == @selector(copy:))
    {
        can = NO;
    }
    NSLog(@"%@ perform action %@ with sender %@.", can ? @"can" : @"cannot", NSStringFromSelector(action), sender);
    return can;
}
爱殇璃 2024-11-25 23:33:34

对于 ios >= 5.1 canPerformAction:(SEL)action withSender:(id)sender 不再工作。

如果您同意禁用粘贴操作,这里有一种方法:

将 UITextFieldDelegate 添加到您的视图控制器并实现这样的方法,

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if(textField == txtEmailRe)
    return ((string.length) > 1 ? NO : YES);
}

这意味着如果用户为每个操作输入多个字符(这意味着用户可能正在粘贴某些内容。)不在文本字段中接受它。

强制用户输入电子邮件等文本字段是一个很好的做法

for ios >= 5.1 canPerformAction:(SEL)action withSender:(id)sender is not working anymore.

If you are ok with just disable paste action here is a method:

add UITextFieldDelegate to you view controller and implement method like this

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if(textField == txtEmailRe)
    return ((string.length) > 1 ? NO : YES);
}

it means that if user enter more than one character for each action (it means that probably user is pasting something.) do not accept it in textfield.

it is a good practice for force user enter textfields like e-mail and

吃颗糖壮壮胆 2024-11-25 23:33:34

莱姆纳尔的答案是正确的。实现 UIWebView 的子类效果很好。这个示例对于UITextView来说是可以的。对于 UIWebView,创建一个自定义子类,如下所示:

//
//  MyUIWebView.h
//

#import <UIKit/UIKit.h>

@interface MyUIWebView : UIWebView

@end

并且:

//
//  MyUIWebView.m
//

#import "MyUIWebView.h"

@implementation MyUIWebView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{
    if (action == @selector(copy:))
        return NO;
    else
        // logic to show or hide other things
}

@end

然后,不要实例化 UIWebView,而是使用 MyUIWebView。

更新

如果想禁用“复制”但保留“定义”(和“翻译”),这可能很有用,这是如何做到的;将上面的 canPerformAction:withSender 替换为:

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

    return [super canPerformAction:action withSender:sender];
}

lemnar's answer is correct. Implementing a subclass of UIWebView works just fine. This example is OK for a UITextView. For a UIWebView, create a custom subclass as follows:

//
//  MyUIWebView.h
//

#import <UIKit/UIKit.h>

@interface MyUIWebView : UIWebView

@end

And:

//
//  MyUIWebView.m
//

#import "MyUIWebView.h"

@implementation MyUIWebView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{
    if (action == @selector(copy:))
        return NO;
    else
        // logic to show or hide other things
}

@end

Then, instead of instantiating UIWebView, use MyUIWebView.

UPDATE:

If wanting to disable "copy" but leave "define" (and "translate",) which can be useful, this is how to do it; replace canPerformAction:withSender above with this:

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

    return [super canPerformAction:action withSender:sender];
}
枕花眠 2024-11-25 23:33:34

这是一个适合我的 iOS5.x 解决方案。它由 Josh Garnham 提出,建议创建一个 UIWebBrowserView 类别来捕获 copy:、paste:、define: 选择器。

http:// /ios-blog.co.uk/iphone-development-tutorials/rich-text-editing-highlighting-and-uimenucontroller-part-3/

@implementation UIWebBrowserView (UIWebBrowserView_Additions)
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    return NO;
}
@end

请注意 FTR:该优秀内容有一个轻微的拼写错误网页。这就是您具体的操作方法。 Apple 将 100% 拒绝此操作。创建一个类别

在此处输入图像描述

(您必须输入在“UIWebBrowserView”中,因为 Xcode 不会调出私有类。).h 和 .m 文件的全文:

// .h file...
#import "UIWebBrowserView+Tricky.h"
@interface UIWebBrowserView : UIView
@end
@interface UIWebBrowserView(Tricky)
@end

// .m file...
#import "UIWebBrowserView+Tricky.h"
@implementation UIWebBrowserView (Tricky)
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
NSLog(@"don't let Apple see this");
return NO;
}
@end

郑重声明,“单击”仍然会调出烦人的拼写检查建议!但除此之外,它确实完全删除了双击上下文菜单,苹果 100% 拒绝了它。

Here is a solution for iOS5.x that works for me. It's by Josh Garnham, suggesting creating a UIWebBrowserView Category to catch the copy:, paste:, define: selectors.

http://ios-blog.co.uk/iphone-development-tutorials/rich-text-editing-highlighting-and-uimenucontroller-part-3/

@implementation UIWebBrowserView (UIWebBrowserView_Additions)
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    return NO;
}
@end

Note just FTR: There's a slight typo on that excellent web page. Here's precisely how you do it. Apple will 100% reject this. Make a category

enter image description here

(You have to type in "UIWebBrowserView" since Xcode won't bring up private classes.) Full text of the .h and .m files:

// .h file...
#import "UIWebBrowserView+Tricky.h"
@interface UIWebBrowserView : UIView
@end
@interface UIWebBrowserView(Tricky)
@end

// .m file...
#import "UIWebBrowserView+Tricky.h"
@implementation UIWebBrowserView (Tricky)
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
NSLog(@"don't let Apple see this");
return NO;
}
@end

For the record, a "single click" will still bring up the annoying spellchecker suggestions! But otherwise it does remove the double-click-context-menu totally, it is 100% rejected by Apple.

怀中猫帐中妖 2024-11-25 23:33:34

我为我的英语感到抱歉。
但有一个想法。

我认为 canPerformAction 方法被调用了很多次,但你只处理它一次。
在这种情况下,我认为可能有另一个UI Control调用了它。例如,UIWebView 中的 UITextView 控件。

我猜你可能会通过故事板生成用户界面。并非故事板中的每个控件都有自己的类。您可以为响应控件定义一个类并重写其 canPerformAction 方法。

I'm sorry for my English.
But there is an idea.

I think the method canPerformAction were called for many times but you just deal with it once.
In this case ,I think there may be another UI Control has called it. For example, the UITextView control in your UIWebView.

I guess you may generate the UI by storyboard. Not every control in storyboard has its own class. You can define a class for the response control and rewrite its canPerformAction method.

怎言笑 2024-11-25 23:33:34

您可以绘制自己的菜单,而不是使用 UIMenuController。这样,您就可以同时显示任意数量的项目,而无需使用“其他”。

You could draw your own menu instead of using UIMenuController. That way, you can have as many items as you want displayed at the same time without using Other.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文