Remove "Copy" menu item from programatically created UITextView IOS

1.2k views Asked by At

I create my UITextView programmatically in my viewDidLoad.
When i select a text, the menu shows me the following :

enter image description here

As it shows, i have added two custom buttons the highlight and unhighlight. I would like to remove the " copy " option and keep all others, so i cannot make it Un-Editable, i need to allow the user to select whatever he wants from the text, but prevent it from copying the content.
I have tried several methods, including this one which all the community is referring to :

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
     NSLog(@"it went in canPerform");
     if (action == @selector(copy:)){

          NSLog(@"It prevented the copy option and hid it from the menu");
          return NO;

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

In order to have a better look at the problem, i tried to log out if the selector is actually taking into consideration the "Copy" option, this is my log :

2015-05-20 11:27:47.637 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.637 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.638 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.638 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.638 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.638 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.638 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.638 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.663 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.664 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.664 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.664 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.664 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.664 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.664 MyApp[56604:11786730] it went in canPerform

2015-05-20 11:27:47.664 MyApp[56604:11786730] it went in canPerform

As it shows, the code is calling the "canPerformAction" since the log shows "It went in canPerform", but it's not recognizing the "copy" action, since the log never showed : "It prevented the copy option and hid it from the menu".
Therefor, my problem is that i need to hide the "Copy" item from the selected text menu. What am i missing ?

3

There are 3 answers

0
Elias Rahme On BEST ANSWER

For All the future developers that will have to deal with this situation, i know how much frustrated you will be, so i will give a FULL tutorial since i came across the correct answer that combines most of the posted answers :

1 - It will only work if you create the UITextView programmatically, it won't work if you have created it using the storyboard, this is the most important part, because if you have an already created UITextView using the storyboard, you won't be able to remove "copy" , you will be capable of removing everything else! Just not the Copy

2 - You will have to subclass the UITextView class, for all new developers, this is done by creating a new class, and choosing it as subclass of the UITextView.

3 - Your .h file will look something like that

//
//  myCustomClass.h
//  myApp
//
//  Created by Elias Rahme on 5/20/15.
//  Copyright (c) 2015 Elias Rahme. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface myCustomClass : UITextView

@end

And your .m file will be like that :

//
//  myCustomClass.m
//  myApp
//
//  Created by Elias Rahme on 5/20/15.
//  Copyright (c) 2015 Elias Rahme. All rights reserved.
//

#import "myCustomClass.h"

@implementation myCustomClass


-(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
     if (action == @selector(copy:)) {
          return NO;
     }
     return [super canPerformAction:action withSender:sender];
}
@end

4 - Now after setting everything up, here comes the tricky part. In the class you want to use the UITextView, include your customClass of course, and afterwards, this is how you call your textView :

First, You have to create a new UITextView, this is done by writing UITextView *newTextView; right above the implementation, as you do to create any variable.

Second, in your actual class, where you have all the work done, go to your .h file , and make sure it looks something like that

#import <UIKit/UIKit.h>

@interface myActuallClassWhereIWantTheActualWorkToBeDone : UIViewController< UITextViewDelegate>{


}

Third, add The following line to your viewDidLoad method :

 newTextView = [[myCustomClass alloc] initWithFrame:CGRectMake(yourX, yourY, yourWidth, yourHeight)];
newTextView.text = @"This is the best small tutorial EVER!!";
 newTextView.delegate = self;

And there you go, run your app, and you will not see the "copy" option! it's an easy yet tricky procedure, and it took me a couple of hours to actually summarize all the web pages i visited! hope everyone enjoys it !

4
Nicolò Ciraci On

canPerformAction(_:withSender:) is a UIResponder method, so if you implement that in the viewController it will trigger only when copy: is called on the viewController. The documentation says that: "Requests the receiving responder to enable or disable the specified command in the user interface."

You have to subclass UITextView and implement that in the subclass, I've created a simple gist for you.

0
Tejas Ardeshna On

try this one

UIMenuItem *textItem1 = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Start", nil) action:@selector(start:)];
UIMenuItem *textItem2 = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Reply", nil) action:@selector(reply:)];

UIMenuItem *textItem3 = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Report Abuse", nil) action:@selector(startreport:)];

[UIMenuController sharedMenuController].menuItems = @[textItem1, textItem2, textItem3];



[[UIMenuController sharedMenuController] setTargetRect:cell.imgBg.frame inView:cell.contentView];
[[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES];