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.