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>.
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;
}
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
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];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With