Jak wyłączyć Kopiuj, Wytnij, Wybierz, Zaznacz wszystko w UITextView


110

Funkcje UITextViewKopiuj, Wytnij, Wybierz, Zaznacz wszystko są wyświetlane domyślnie po naciśnięciu ekranu. Ale w moim projekcie UITextFieldjest tylko do odczytu. Nie potrzebuję tej funkcjonalności. Powiedz mi, jak wyłączyć tę funkcję.


3
place [UIMenuController sharedMenuController] .menuVisible = NO; in - (BOOL) canPerformAction: (SEL) akcja withSender: (id) metoda nadawcy.
— ravoorinandan

Odpowiedzi:


108

Najłatwiejszym sposobem wyłączenia operacji wklejania jest utworzenie podklasy, UITextViewktóra przesłania canPerformAction:withSender:metodę zwracania NOdziałań, na które nie chcesz zezwolić:

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

Zobacz także UIResponder


1
@rpetrichm, użyłem twojego rozwiązania, kopiuj / wklej / wytnij / wybierz / wybierzWszystkie opcje są wyłączone, ale wciąż nadchodzi Zastąp ... | BIU | Zdefiniuj opcje. Chcę wyłączyć to pełne menu.
— Ameet Dhas

3
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }- zablokować wszystkie opcje
— Islam Q.

To świetnie, ale nie wiem, jak to zrobić dla UISearchBar - ponieważ wewnątrz znajduje się również pole tekstowe, pomyślałem, że mogę nadpisać metodę podklasy UISearchBar, ale to niestety nie działa. Jakieś pomysły na to?
— borchero

mam wiele kontrolek. jak zezwolić na kopiowanie wklejania tylko na jednej kontrolce?
— Gaucho

To nie działa dla UITextView, chociaż widziałem to rozwiązanie sugerowane w wielu miejscach na SO. Czy ktoś wymyślił, jak to zrobić?
— Pigpocket,

67

Podklasa UITextView i nadpisanie canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
    return NO;
}

Zwróć uwagę, że dotyczy to tylko nieedytowalnych UITextViews! Nie testowałem tego na edytowalnych ...


Myślę return NO;o - (BOOL)canPerformAction:(SEL)action withSender:(id)sendermetodzie jest lepszym rozwiązaniem.
— Islam Pytanie

29

Jeśli chcesz wyłączyć wycinanie / kopiowanie / wklejanie we wszystkich UITextView swoich aplikacjach, możesz użyć kategorii z:

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

Zapisuje podklasę ... :-)


3
możesz również umieścić to tylko w swoim /, pliku, w którym potrzebujesz tego zachowania.
— markus_p

4
Działa to tylko jako efekt uboczny i zapobiega UITextViewzachowywaniu się zgodnie z oczekiwaniami, na przykład, gdy można go edytować i można go dotknąć. To dużo do przesłonięcia canPerformAction:withSender:; do tego służy protokół.
— jdc

16
Nie można bezpiecznie przesłonić metody przy użyciu kategorii. To jest niezdefiniowane zachowanie. Musisz podklasę, aby bezpiecznie przesłonić metodę.
— Rob Napier

2
Uwaga: dotyczy to wszystkich UITextViews w Twojej aplikacji. Przez większość czasu nie jest idealny.
— bbrame

2
Zwróć również uwagę, że Apple odradza to : „Jeśli nazwa metody zadeklarowanej w kategorii jest taka sama, jak metoda z oryginalnej klasy lub metoda z innej kategorii tej samej klasy (lub nawet nadklasy), zachowanie jest nie zdefiniowano, która implementacja metody jest używana w czasie wykonywania ... [i] może powodować problemy podczas używania kategorii do dodawania metod do standardowych klas Cocoa lub Cocoa Touch. "
— Rob

29

To było dla mnie najlepsze działające rozwiązanie:

UIView *overlay = [[UIView alloc] init];  
[overlay setFrame:CGRectMake(0, 0, myTextView.contentSize.width, myTextView.contentSize.height)];  
[myTextView addSubview:overlay];  
[overlay release];

z: https://stackoverflow.com/a/5704584/1293949


3
niezły, bez podklas!
— Martin Reichl,

7
Uwielbiam podejście do taśmy klejącej i drutu do belowania. Chciałbym móc dać Ci jeszcze raz :) Zamiast tego, oto złota gwiazda: i.imgur.com/EXLFt1Z.jpg
— jdc

22

@rpetrich answer zadziałało dla mnie. Wysyłam rozszerzony kod na wypadek, gdyby zaoszczędził komuś trochę czasu.

W moim przypadku nie chcę żadnego wyskakującego okienka, ale chcę, aby UITextField mógł zostać pierwszym respondentem.

Niestety, po dotknięciu i przytrzymaniu pola tekstowego nadal pojawia się wyskakujące okienko lupy.

@interface NoSelectTextField : UITextField

@end

@implementation NoSelectTextField

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(paste:) ||
        action == @selector(cut:) ||
        action == @selector(copy:) ||
        action == @selector(select:) ||
        action == @selector(selectAll:) ||
        action == @selector(delete:) ||
        action == @selector(makeTextWritingDirectionLeftToRight:) ||
        action == @selector(makeTextWritingDirectionRightToLeft:) ||
        action == @selector(toggleBoldface:) ||
        action == @selector(toggleItalics:) ||
        action == @selector(toggleUnderline:)
        ) {
            return NO;
    }
    return [super canPerformAction:action withSender:sender];
}

@end

Szybki 4

class NoSelectTextField: UITextField {

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(paste(_:)) ||
            action == #selector(cut(_:)) ||
            action == #selector(copy(_:)) ||
            action == #selector(select(_:)) ||
            action == #selector(selectAll(_:)) ||
            action == #selector(delete(_:)) ||
            action == #selector(makeTextWritingDirectionLeftToRight(_:)) ||
            action == #selector(makeTextWritingDirectionRightToLeft(_:)) ||
            action == #selector(toggleBoldface(_:)) ||
            action == #selector(toggleItalics(_:)) ||
            action == #selector(toggleUnderline(_:)) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
    }

}

1
Prosimy o przesłanie szybkiej wersji również dla tego. Dziękuję Ci.
— Salman Khakwani

@pinch: tnx. Nadal trzyma wodę w iOS 12.1.3.
— YvesLeBorg

20

Jeśli nie potrzebujesz UITextView do przewijania, najprostszym rozwiązaniem, które nie obejmuje podklas, jest po prostu wyłączenie interakcji użytkownika dla widoku tekstu:

textField.userInteractionEnabled = NO;

2
Eliminuje to stukanie w linki itp., Jeśli tak jest w widoku tekstu. Należy zauważyć, że nie jest to dobre rozwiązanie w przypadku chęci ukrycia opcji zaznaczania / kopiowania / wklejania, ale także pozostawienia włączonego pewnego poziomu interakcji.
— barfoon

3
Pomyślałem, że to oczywiste.
— Luke Redpath

Używam pól tekstowych jako etykiet do obrazków w grze i nie chcę, aby pojawiła się lupa i nie ma powodu, aby kopiować tekst. To działa świetnie dla mnie. Używam tekstu stylizowanego w UIWebView i ta sama linia również tam działa.
— JScarry

15

Najłatwiejszym sposobem jest utworzenie podklasy UITextView, która przesłania canPerformAction: withSender:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender    
{    
     [UIMenuController sharedMenuController].menuVisible = NO;  //do not display the menu
     [self resignFirstResponder];                      //do not allow the user to selected anything
     return NO;
}

Jest to najlepsze rozwiązanie, jeśli chodzi o możliwość wpisywania tekstu, ale nic poza tym, i pozwala na to, aby dotknięcia pola tekstowego nie były już „przechwytywane”. Robi to, czego chciał PO, i nie tylko.
— hlfcoding

13

Kiedy zwrócę NIE w canPerformAction na iOS 7, otrzymam wiele błędów takich jak ten:

<Error>: CGContextSetFillColorWithColor: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.

Moje rozwiązanie jest następujące:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
    }];
    return [super canPerformAction:action withSender:sender];
}

Sztuczka polega na tym, aby w kolejnym cyklu w głównej kolejce ukryć kontroler menu (tuż po jego wyświetleniu).


bardzo miły. jedynym problemem jest to, że mam 2 textviews i jeden textField i chcę uniknąć kopiowania i wklejania tylko w polach textView. jak zidentyfikować, kto zadzwonił do canPerformAction? zmienną nadawcy jest UIMenuController
— Gaucho

1
Działa na podklasie UITextField (lub UITextView). Jeśli nie użyjesz utworzonej przez siebie podklasy, nie przyniesie to żadnego efektu. Np. Utworzyłem TextFieldWithoutCopyPaste i użyłem tego, w którym nie chciałem mieć funkcji kopiowania wklejania.
— Adam Wallner

ok masz rację. Ale w moim przypadku textView potrzebuje podklasy, aby używać canPerformAction, a textField potrzebuje podklasy, aby używać textFieldDidBeginEditing w celu animowania okna, gdy wyświetlana jest klawiatura. animacja przesuwa okno za pomocą klawiatury. Używam tej metody, aby uniknąć zasłaniania pola tekstowego przez klawiaturę.
— Gaucho

10

Jest to najłatwiejszy sposób na wyłączenie całego menu Wybierz / Kopiuj / Wklej w UITextView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{    
    [UIMenuController sharedMenuController].menuVisible = NO;
    return NO;    
}

Działa również dla UITextField. Dzięki za udostępnienie.
— Gaurav Srivastava

1
Używam powyższego kodu, ale nadal otrzymuję menu, jak to wyłączyć, pomóż mi.
— Bittoo

4

Od iOS 7 istnieje właściwość na UITextView:

 @property(nonatomic,getter=isSelectable) BOOL selectable;

Dzięki temu widok nie zezwala na zaznaczanie tekstu. U mnie działa świetnie.


4

Jeśli chcesz zastąpić klawiaturę, powiedzmy, UIPickerjako inputView(oczywiście z paskiem narzędzi jako inputAccesotyView), to obejście może pomóc ...

  • Wprowadzić w życie textFieldShouldBeginEditing:
  • wewnątrz umieścić textField.userInteractionEnabled = NO;
  • Następnie, gdy masz zamiar zamknąć UIPickerView, ustaw go na TAK.

W ten sposób będziesz mógł dotknąć UITextFieldi wyświetlić opcje do wyboru UIPickerView, w tym momencie UITextFieldrzeczywiście nie zareagowałbyś na żadne zdarzenie dotykowe (obejmuje to dotknięcie i przytrzymanie do wycinania, kopiowania i wklejania). Musisz jednak pamiętać, aby ustawić go z powrotem na TAK podczas zamykania konta, UIPickerViewale nie będziesz mieć dostępu do swojegoUIPickerView ponownie.

Jedynym momentem, w którym to się nie powiedzie, jest to, że użytkownik zaczyna od dotknięcia i przytrzymania przycisku UITextView, a następnie po raz pierwszy zobaczysz wycinanie, kopiowanie i wklejanie. Dlatego zawsze należy sprawdzać poprawność wprowadzonych danych. To najłatwiejsza rzecz, jaką przychodzi mi do głowy. Inną opcją było użycie UILabeltekstu tylko do odczytu, ale brakuje Ci wielu wspaniałych funkcji z UITextView.


4

Podklasa UITextView - swift 4.0

     override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }

Jakie dziwne? nadal pokazuje opcję „Wklej”, ale nie rób tego, jeśli zostanie naciśnięty ...
— iOS Flow

4

Jeśli chcesz wyłączyć wyskakujące okienko, UITextFieldwypróbuj tę UITextFieldDelegatemetodę, aby przełączyć isUserInteractionEnabled.

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    textField.isUserInteractionEnabled = false
    return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    textField.isUserInteractionEnabled = true
    return true
}

3

Można to łatwo zrobić w scenorysie (Xcode 6). Po prostu odznacz opcję Edytowalne i Wybieralne w Inspektorze atrybutów. Nadal możesz przewijać widok tekstu.wprowadź opis obrazu tutaj


3

To zadziałało dla mnie. Upewnij się, że dzwonisz do resignFirstResponder w textView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
  [self.textView resignFirstResponder];
  return NO;
}

2

Podałem tutaj działającą odpowiedź , aby wyłączyć zaznaczanie tekstu + lupę, zachowując włączone klikalne linki. Mam nadzieję, że to pomoże:

Po dość długich próbach udało mi się zatrzymać zaznaczanie tekstu, powiększanie i utrzymywanie wykrywania danych (klikalne linki itp.), Zastępując addGestureRecognizer w podklasie UITextView, pozwalając tylko UILongPressGestureRecognizer opóźniać zakończenie dotyku:

UIUnselectableTextView.m

-(void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
    if([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] && gestureRecognizer.delaysTouchesEnded)
    {
        [super addGestureRecognizer:gestureRecognizer];
    }
}

2

W przypadku Swift 3 zmieniono na:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
}

2

Możesz to naprawić w swoim storyboardzie, odznaczając te pola:

wprowadź opis obrazu tutaj

Lub możesz ustawić programowo w następujący sposób:

textView.selectable = false
textView.editable = false

1

Zrobiłem to. Na moim UITextViewbardzo łatwo wyłączyłem opcję wycinania, kopiowania, zaznaczania itp.

Umieściłem UIVieww tym samym miejscu, w którym umieściłem UITextView, ale na self.viewi dodałem touchDelegatemetodę w następujący sposób:

(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *scrollTouch=[touches anyObject];
    if(scrollTouch.view.tag==1)
    {
        NSLog(@"viewTouched");
        if(scrollTouch.tapCount==1)
            [textView1 becomeFirstResponder];
        else if(scrollTouch.tapCount==2)
        {
            NSLog(@"double touch");
            return;
        }

    }
}

i to zadziałało dla mnie. Dziękuję Ci.


1

Szybki

textView.selectable = false // disable text selection (and thus copy/paste/etc)

Związane z

textView.editable = false // text cannot be changed but can still be selected and copied
textView.userInteractionEnabled = false // disables all interaction, including scrolling, clicking on links, etc.

1

Jeśli chcesz dodać niestandardową opcję do swojego UITextView, ale wyłączyć istniejące funkcje, oto jak to zrobić w Swift 3 :

Aby wyłączyć kopiowanie, wklejanie, wycinanie, utwórz podklasę i nadpisz następujące elementy:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
} 

W kontrolerze ViewController masz swój CustomTextView dodaj następujące elementy, aby dodać opcje:

  let selectText = UIMenuItem(title: "Select", action: #selector(ViewController.selected))

    func selected() {

    if let selectedRange = textView.selectedTextRange, let 
     selectedText = textView.text(in: selectedRange) {

     }


    print("User selected text: \(selectedText)")

    }

1

Ta metoda całkowicie wyłączy menu Wybierz, Zaznacz wszystko, Wklej. Jeśli nadal otrzymujesz inną akcję, po prostu dodaj ją do warunku if, jak poniżej.

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender // This is to disable select / copy / select all / paste menu
    {
        if (action == @selector(copy:) || action == @selector(selectAll:) || action == @selector(select:) || action == @selector(paste:))
            return NO;
        return [super canPerformAction:action withSender:sender];
    }

0

Możesz po prostu utworzyć taką kategorię:

UITextView + Selectable. H

@interface UITextView (Selectable)

@property (nonatomic, assign, getter = isTextSelectable) bool textSelectable;

@end

UITextView + Selectable. M

#import "UITextView+Selectable.h"

#import <objc/runtime.h>

#define TEXT_SELECTABLE_PROPERTY_KEY @"textSelectablePropertyKey"

@implementation UITextView (Selectable)

@dynamic textSelectable;

-(void)setTextSelectable:(bool)textSelectable {
    objc_setAssociatedObject(self, TEXT_SELECTABLE_PROPERTY_KEY, [NSNumber numberWithBool:textSelectable], OBJC_ASSOCIATION_ASSIGN);
}

-(bool)isTextSelectable {
    return [objc_getAssociatedObject(self, TEXT_SELECTABLE_PROPERTY_KEY) boolValue];
}

-(bool)canBecomeFirstResponder {
    return [self isTextSelectable];
}

@end

1
To nie jest dobry sposób na rozwiązanie tego problemu. Po pierwsze wpływa na wszystko, tak jak w kategorii. Po drugie, użycie powiązanych obiektów do raczej łatwego zadania może później spowodować więcej problemów z debugowaniem (dlaczego to działa tak, kiedy zapomnisz, co zrobiłeś) niż przynosić zysk. Moim zdaniem dobrze jest tego unikać, gdy tylko jest to możliwe. Sprawia, że ​​kod jest trudniejszy do znalezienia, debugowania i zrozumienia przez nowego programistę w projekcie.
— Vive

0

Podklasy UITextViewi nadpisywanie - (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizerto kolejna możliwość wyłączenia niechcianych działań.

Użyj klasy obiektu gestureRecognizer-object, aby zdecydować, czy akcja powinna zostać dodana, czy nie.


0

(SWIFT) Jeśli chcesz mieć tylko podstawowe pole tekstowe bez opcji menu ani szkła powiększającego, utwórz podklasę UITextField zwracającą false do gestRecognizerShouldBegin:

class TextFieldBasic: UITextField {
    override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {

        return false
    }
}

Spowoduje to pominięcie wszystkich funkcji dotykowych w polu tekstowym, ale nadal umożliwi używanie wyskakującej klawiatury do dodawania / usuwania znaków.

Jeśli używasz scenorysu, po prostu przypisz nowo utworzoną klasę do pola tekstowego lub jeśli programowo tworzysz pole tekstowe:

var basicTextField = TextFieldBasic()
basic = basicTextField(frame: CGRectMake(10, 100, 100,35))
basic.backgroundColor = UIColor.redColor()
self.view.addSubview(basic)

basic.becomeFirstResponder()

0
override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool 
{
    NSOperationQueue .mainQueue().addOperationWithBlock({ () -> Void in   

        [UIMenuController .sharedMenuController() .setMenuVisible(false, animated: true)]

    })
    return super.canPerformAction(action, withSender: sender)}

0

Szybki 3

Aby to zrobić, musisz utworzyć podklasę swojego UITextView i umieścić tę metodę.

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if (action == #selector(copy(_:))) {
            return false
        }

        if (action == #selector(cut(_:))) {
            return false
        }

        if (action == #selector(paste(_:))) {
            return false
        }

        return super.canPerformAction(action, withSender: sender)
    }

0

UITextView ma dwie właściwości, które zrobią to, czego potrzebujesz: isSelectable i isEditable .

Ustawienie isEditable na false pozwoli uniknąć użytkownikowi edycji tekstu, a ustawienie isSelectable na false pozwoli uniknąć użytkownikowi wybierania tekstu w Twoim textView, co zapobiegnie wyświetlaniu menu akcji.


0

Proszę znaleźć przykładowy kod w celach informacyjnych:

 override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(copy(_:)) || action == #selector(paste(_:)) || action == #selector(UIResponderStandardEditActions.paste(_:)) ||
            action == #selector(replace(_:withText:)) ||
            action == #selector(UIResponderStandardEditActions.cut(_:)) ||
        action == #selector(UIResponderStandardEditActions.select(_:)) ||
        action == #selector(UIResponderStandardEditActions.selectAll(_:)) ||
        action == #selector(UIResponderStandardEditActions.delete(_:)) ||
        action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight(_:)) ||
        action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft(_:)) ||
        action == #selector(UIResponderStandardEditActions.toggleBoldface(_:)) ||
        action == #selector(UIResponderStandardEditActions.toggleItalics(_:)) ||
        action == #selector(UIResponderStandardEditActions.toggleUnderline(_:)) ||
        action == #selector(UIResponderStandardEditActions.increaseSize(_:)) ||
        action == #selector(UIResponderStandardEditActions.decreaseSize(_:))

       {
            return false
        }

        return true
    }

-1

Użyj func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }zamiast textFieldShouldBeginEditing.

class ViewController: UIViewController , UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        //Show date picker
        let datePicker = UIDatePicker()
        datePicker.datePickerMode = UIDatePickerMode.date
        textField.tag = 1
        textField.inputView = datePicker
    }

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        if textField.tag == 1 {
            textField.text = ""
            return false
        }

        return true
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if textField.tag == 1 {
            textField.text = ""
            return false
        }

        return true
    }
}

Utwórz nową klasę o nazwie StopPasteAction.swift

import UIKit

class StopPasteAction: UITextField {

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
}

Dodaj klasę nową klasę z bieżącym TextField

wprowadź opis obrazu tutaj

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.