Włącz kopiowanie i wklejanie na UITextField bez edytowalności

Chcę, aby tekst w UITextField (lub najlepiej UILabel) był nieedytowalny , ale jednocześnie dać użytkownikowi możliwość skopiowania go do wklejenia gdzie indziej.

Author: Harris, 2009-12-17

6 answers

Moje ostateczne rozwiązanie było następujące:

Utworzyłem podklasę UILabel (UITextField powinno działać tak samo), która wyświetla Kontroler UIMenuController po naciśnięciu przycisku. CopyableLabel.m wygląda tak:

@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
 25
Author: mrueg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-30 14:35:55

To pytanie jest dość stare i dziwię się, że nikt nie opublikował rozwiązania bez podklasowania. Pomysł przedstawiony w odpowiedzi @mrueg jest poprawny, ale nie trzeba niczego podklasować. Po prostu natknąłem się na ten problem i rozwiązałem go w ten sposób:

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;
}

Jeśli chcesz, aby to działało dla UILabel, powinno działać w ten sam sposób, po prostu dodając rozpoznawanie gestów stukania zamiast używać metody delegate.

 6
Author: Shinigami,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-02 20:20:00

To zrobi wszystko, czego potrzebujesz. Będzie można skopiować. Ale nie można edytować i nie pokazuje klawiatury ani kursora.

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
    }

}
 4
Author: Harris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-22 17:10:23

Spróbuj zamiast tego UITextView (podejrzewam, że to zadziała jak {[1] } dla Ciebie). Testowałem to z jego właściwością editable ustawioną na NO i podwójne stukanie w Kopiowanie działało dla mnie.

 3
Author: Alex Reynolds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-17 10:49:05

Innym rozwiązaniem jest utrzymanie UITextField włączone, ale programowo uniemożliwia jego edycję. Odbywa się to za pomocą następującej metody delegata:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    return NO;
}

Nie jestem jednak świadomy możliwych ograniczeń, obecnie odpowiada moim potrzebom.

 1
Author: keeshux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-18 13:18:40

Poniższy kod mnie uratował.

textField.addTarget(target, action: "textFieldEditingDidEndAction:", forControlEvents: [.EditingDidEnd])

Wydaje się, że Paste jest pojedynczym i kompletnym wydarzeniem edycji.

 0
Author: Veight Zhou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-17 09:19:51