Enable copy and paste on UITextField without making it editable Enable copy and paste on UITextField without making it editable ios ios

Enable copy and paste on UITextField without making it editable


My final solution was the following:

I created a subclass of UILabel (UITextField should work the same) that displays a UIMenuController after being tapped. CopyableLabel.m looks like this:

@implementation CopyableLabel- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {if(action == @selector(copy:)) {    return YES;}else {    return [super canPerformAction:action withSender:sender];}}- (BOOL)canBecomeFirstResponder {return YES;}- (BOOL)becomeFirstResponder {if([super becomeFirstResponder]) {    self.highlighted = YES;    return YES;}return NO;}- (void)copy:(id)sender {UIPasteboard *board = [UIPasteboard generalPasteboard];[board setString:self.text];self.highlighted = NO;[self resignFirstResponder];}- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {if([self isFirstResponder]) {    self.highlighted = NO;    UIMenuController *menu = [UIMenuController sharedMenuController];    [menu setMenuVisible:NO animated:YES];    [menu update];    [self resignFirstResponder];}else if([self becomeFirstResponder]) {    UIMenuController *menu = [UIMenuController sharedMenuController];    [menu setTargetRect:self.bounds inView:self];    [menu setMenuVisible:YES animated:YES];}}@end


This question is pretty old and I'm surprised nobody has posted a solution without subclassing. The idea presented in @mrueg's answer is correct, but you shouldn't need to subclass anything. I just came across this problem and solved it like this:

In my view controller:

- (void)viewDidLoad {    self.textField.delegate = self;    self.textField.text = @"Copyable, non-editable string.";}- (BOOL)canBecomeFirstResponder {    return YES;}- (void)copyTextFieldContent:(id)sender {    UIPasteboard* pb = [UIPasteboard generalPasteboard];    pb.string = self.textField.text;}- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {    // UIKit changes the first responder after this method, so we need to show the copy menu after this method returns.    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{         [self becomeFirstResponder];         UIMenuController* menuController = [UIMenuController sharedMenuController];         UIMenuItem* copyItem = [[UIMenuItem alloc] initWithTitle:@"Copy"                                                           action:@selector(copyTextFieldContent:)];         menuController.menuItems = @[copyItem];         CGRect selectionRect = textField.frame;         [menuController setTargetRect:selectionRect inView:self.view];         [menuController setMenuVisible:YES animated:YES];     });     return NO;}

If you want to make this work for a UILabel, it should work the same way with just adding a tap gesture recognizer instead of using the delegate method.


This will do everything you need. Will be copyable. But not editable, and won't show a keyboard or a cursor.

class ViewController: UIViewController {    @IBOutlet weak var copyableUneditableTextfield: UITextField!    override func viewDidLoad() {        super.viewDidLoad()        copyableUneditableTextfield.delegate = self        copyableUneditableTextfield.inputView = UIView()   //prevents keyboard             copyableUneditableTextfield.tintColor = .clear     //prevents cursor        copyableUneditableTextfield.text = "Some Text You Want User To Copy But Not Edit"    }}extension ViewController: UITextFieldDelegate {    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {        return false //prevents editing    }}