Come disabilitare Copia, Taglia, Seleziona, Seleziona tutto in UITextView


110

Le funzionalità UITextViewdi Copia, Taglia, Seleziona, Seleziona tutto vengono visualizzate per impostazione predefinita quando si preme sullo schermo. Ma, nel mio progetto, UITextFieldè di sola lettura. Non ho bisogno di questa funzionalità. Per favore dimmi come disabilitare questa funzione.


3
place [UIMenuController sharedMenuController] .menuVisible = NO; in - (BOOL) canPerformAction: (SEL) azione withSender: (id) metodo del mittente.
ravoorinandan

Risposte:


108

Il modo più semplice per disabilitare le operazioni di montaggio è creare una sottoclasse UITextViewche sovrascrive il canPerformAction:withSender:metodo da restituire NOper le azioni che non si desidera consentire:

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

Vedi anche UIResponder


1
@rpetrichm, ho usato la tua soluzione, copia / incolla / taglia / seleziona / seleziona Tutte le opzioni sono disabilitate ma c'è ancora in arrivo Sostituisci ... | BIU | Definisci opzioni. Voglio disabilitare quel menu completo.
Ameet Dhas

3
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }- per bloccare tutte le opzioni
Islam Q.

È fantastico, tuttavia non so come farlo per UISearchBar - poiché all'interno è presente anche un campo di testo, pensavo di poter sovrascrivere il metodo della sottoclasse di UISearchBar ma sfortunatamente non funziona. Qualche idea per questo?
borchero

ho molti controlli. come consentire copia incolla solo su un controllo?
Gaucho

Questo non funziona per UITextView, anche se ho visto questa soluzione suggerita in diversi posti su SO. Qualcuno ha capito come farlo?
Pigpocket

67

Sottoclasse UITextView e sovrascrivi canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
    return NO;
}

Nota che questo vale solo per UITextViews non modificabili! Non l'ho testato su quelli modificabili ...


Penso che return NO;il - (BOOL)canPerformAction:(SEL)action withSender:(id)sendermetodo sia un'opzione migliore.
Islam Q.

29

Se vuoi disabilitare taglia / copia / incolla su tutta la UITextView tua applicazione puoi usare una categoria con:

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

Salva una sottoclasse ... :-)


3
puoi anche metterlo solo nel tuo file /, dove hai bisogno di questo comportamento.
markus_p

4
Questo funziona solo come effetto collaterale e impedisce che si UITextViewcomporti come previsto quando, ad esempio, è modificabile e viene toccato. È molto da ignorare canPerformAction:withSender:; ecco a cosa serve il protocollo.
jdc

16
Non è possibile sovrascrivere in modo sicuro un metodo utilizzando una categoria. Questo è un comportamento indefinito. È necessario creare una sottoclasse per sovrascrivere in modo sicuro un metodo.
Rob Napier

2
Nota: questo si applicherà a tutti gli UITextViews nella tua applicazione. Non è l'ideale per la maggior parte del tempo.
bbrame

2
Si noti inoltre che Apple sconsiglia questo : "Se il nome di un metodo dichiarato in una categoria è lo stesso di un metodo nella classe originale o di un metodo in un'altra categoria della stessa classe (o anche di una superclasse), il comportamento è undefined sull'implementazione del metodo utilizzata in fase di runtime ... [e] può causare problemi quando si utilizzano categorie per aggiungere metodi alle classi Cocoa o Cocoa Touch standard. "
Rob


22

La risposta di @rpetrich ha funzionato per me. Sto postando il codice espanso nel caso in cui faccia risparmiare un po 'di tempo a qualcuno.

Nel mio caso non voglio alcun popup, ma voglio che UITextField sia in grado di diventare il primo risponditore.

Sfortunatamente, visualizzi ancora il popup della lente di ingrandimento quando tocchi e tieni premuto il campo di testo.

@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

Swift 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
Pubblica anche una versione rapida per questo. grazie.
Salman Khakwani

@pinch: tnx. Tiene ancora l'acqua in iOS 12.1.3.
YvesLeBorg

20

Se non hai bisogno di UITextView per scorrere, la soluzione più semplice che non coinvolge la sottoclasse è semplicemente disabilitare l'interazione dell'utente per la visualizzazione del testo:

textField.userInteractionEnabled = NO;

2
Questo toglie il tocco sui collegamenti ecc. Se questo è ciò che è nella visualizzazione di testo. Va notato che questa non è una buona soluzione per voler nascondere la selezione / copia / incolla, ma anche mantenere abilitato un certo livello di interazione.
barfoon

3
Beh, avrei pensato che sarebbe stato ovvio.
Luke Redpath

Uso i campi di testo come etichette per le immagini in un gioco e non voglio che appaia la lente di ingrandimento e non c'è motivo di copiare il testo. Questo funziona alla grande per me. Sto usando testo in stile in un UIWebView e la stessa riga funziona anche lì.
JScarry

15

Il modo più semplice è creare una sottoclasse di UITextView che sostituisca 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;
}

Questa è la migliore soluzione per poter digitare del testo ma nient'altro, e permette che i tocchi sul campo di testo non vengano più "intercettati". Questo fa quello che voleva l'OP e altro ancora.
hlfcoding

13

Quando restituisco NO in canPerformAction su iOS 7 riceverò molti errori come questo:

<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.

La mia soluzione è la seguente:

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

Il trucco è nascondere il controller del menu nel ciclo successivo sulla coda principale (subito dopo che è stato visualizzato).


veramente bello. l'unico problema è che ho 2 textviews e un textField e voglio evitare il copia-incolla solo sui campi textView. come identificare chi ha chiamato canPerformAction? la variabile mittente è UIMenuController
Gaucho

1
Funziona sulla sottoclasse di UITextField (o UITextView). Se non usi la sottoclasse che hai creato, non avrà alcun effetto. Ad esempio, ho creato un TextFieldWithoutCopyPaste e l'ho usato in cui non volevo avere la funzionalità di copia incolla.
Adam Wallner

ok hai ragione. Ma nel mio caso, textView ha bisogno di una sottoclasse per usare canPerformAction e textField ha bisogno di una sottoclasse per usare textFieldDidBeginEditing per animare la finestra quando viene mostrata la tastiera. l'animazione sposta la finestra con la tastiera. Uso questo metodo per evitare che la tastiera copra il textField.
Gaucho

10

Questo è il modo più semplice per disabilitare l'intero menu Seleziona / Copia / Incolla in un UITextView

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

Funziona anche per UITextField. Grazie per la condivisione.
Gaurav Srivastava

1
Sto usando il codice sopra ancora ricevo il menu come disabilitare che per favore aiutami.
Bittoo

4

Da iOS 7 c'è una proprietà su UITextView:

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

Ciò impedisce a una vista di consentire le selezioni di testo. Funziona alla grande per me.


4

Se stai cercando di sostituire la tastiera con una, diciamo, UIPickercome inputView(con ovviamente una barra degli strumenti come una inputAccesotyView), allora questa soluzione alternativa potrebbe aiutare ...

  • Strumento textFieldShouldBeginEditing:
  • mettere dentro textField.userInteractionEnabled = NO;
  • Quindi, quando stai per chiudere il UIPickerView, impostalo su YES.

In questo modo, saresti in grado di toccare UITextFielde mostrare le opzioni tra cui scegliere UIPickerView, in questo momento UITextField, in effetti, non reagirebbe a nessun evento di tocco (questo include toccare e tenere premuto per tagliare, copiare e incollare). Tuttavia, dovresti ricordarti di impostarlo di nuovo su SÌ quando chiudi il tuo, UIPickerViewtuttavia non sarai in grado di accedervi di UIPickerViewnuovo.

L'unico momento in cui fallisce è quando l'utente inizia toccando e tenendo premuto il UITextView, quindi vedrai tagliare copia e incolla di nuovo per la prima volta. Questo è il motivo per cui dovresti sempre convalidare i tuoi input. Questo è il modo più semplice a cui riesco a pensare. L'altra opzione era usare un UILabelper il testo di sola lettura ma ti mancano molte ottime funzionalità da UITextView.


4

Sottoclasse UITextView - swift 4.0

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

Che strano? mostra ancora l'opzione "Incolla" ma non farlo se premuto ...
iOS Flow

4

Se vuoi disabilitare il popup per, UITextFieldprova questo UITextFieldDelegatemetodo per attivare / disattivare isUserInteractionEnabled.

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

3

Questo può essere fatto facilmente nello storyboard (Xcode 6). Basta deselezionare Modificabile e Selezionabile in Attributes Inspector. È comunque possibile scorrere la visualizzazione del testo.inserisci qui la descrizione dell'immagine


3

Questo ha funzionato per me. Assicurati di chiamare resignFirstResponder su textView

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

2

Ho fornito una risposta funzionante qui per disabilitare la selezione del testo + lente d'ingrandimento, mantenendo i collegamenti cliccabili abilitati Spero che aiuti:

Dopo un lungo periodo di tentativi, sono riuscito a interrompere la selezione del testo, l'ingrandimento e il mantenimento del rilevamento dei dati (collegamenti selezionabili, ecc.) Sovrascrivendo addGestureRecognizer su una sottoclasse UITextView consentendo solo a UILongPressGestureRecognizer di ritardare la fine del tocco:

UIUnselectableTextView.m

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

2

Per Swift 3 è cambiato in:

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

2

Puoi risolvere questo problema nel tuo storyboard deselezionando queste caselle:

inserisci qui la descrizione dell'immagine

Oppure puoi impostare programmaticamente in questo modo:

textView.selectable = false
textView.editable = false

1

L'ho fatto. Sul mio UITextViewho disabilitato molto facilmente l'opzione taglia, copia, seleziona, ecc.

Ho posizionato UIViewa nello stesso punto in cui avevo posizionato UITextView, ma su self.viewe ho aggiunto un touchDelegatemetodo come segue:

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

    }
}

e ha funzionato per me. Grazie.


1

veloce

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

Relazionato

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

Se vuoi aggiungere un'opzione personalizzata a UITextView ma disabilitare le funzioni esistenti, ecco come lo fai su Swift 3 :

Per disabilitare la funzionalità di copia, incolla, taglio, creare una sottoclasse e sovrascrivere quanto segue:

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

Sul ViewController hai il tuo CustomTextView aggiungere quanto segue per aggiungere le tue opzioni:

  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

Questo metodo disabiliterà completamente il menu Seleziona, Seleziona tutto, Incolla. Se ottieni ancora qualche altra azione, aggiungila alla condizione if come di seguito.

- (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

Puoi semplicemente creare una categoria come questa:

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
Questo non è un buon modo per risolverlo. In primo luogo colpisce tutto, poiché è nella categoria. In secondo luogo, l'utilizzo di oggetti associati per attività piuttosto semplici può causare più problemi in seguito con il debug (perché funziona in questo modo quando dimentichi quello che hai fatto) che dare profitto. È bene evitarlo quando possibile secondo me. Rende il codice meno facile da trovare, eseguire il debug e comprendere dal nuovo programmatore del progetto.
Vive

0

La creazione di sottoclassi UITextViewe l'override - (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizersono un'altra possibilità per disabilitare le azioni indesiderate.

Usa la classe gestureRecognizerdell'oggetto -object per decidere se l'azione deve essere aggiunta o meno.


0

(SWIFT) Se vuoi solo un campo di testo di base senza nessuna delle opzioni di menu o lente di ingrandimento, crea una sottoclasse di UITextField che restituisce false a gestureRecognizerShouldBegin:

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

        return false
    }
}

Ciò aggirerà tutte le funzionalità di tocco nel campo di testo, ma ti consentirà comunque di utilizzare la tastiera popup per aggiungere / rimuovere caratteri.

Se stai usando lo storyboard, assegna semplicemente la classe appena creata al campo di testo o se stai creando un campo di testo in modo programmatico:

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

Swift 3

Per fare ciò, è necessario creare una sottoclasse di UITextView e inserire questo metodo.

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 ha due proprietà che faranno ciò di cui hai bisogno: isSelectable e isEditable .

Impostando isEditable a false eviterai che l'utente modifichi il testo e impostando isSelectable su false eviterai che l'utente selezioni il testo all'interno del tuo textView in modo da impedire la visualizzazione del menu delle azioni.


0

Trova il codice di esempio per riferimento:

 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

Utilizzare func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }al posto di 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
    }
}

Crea una nuova classe con il nome StopPasteAction.swift

import UIKit

class StopPasteAction: UITextField {

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

Aggiungi la nuova classe con il tuo TextField corrente

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.