Como desativar Copiar, Cortar, Selecionar, Selecionar Tudo em UITextView


110

A funcionalidade de UITextViewCopiar, Cortar, Selecionar, Selecionar Tudo é exibida por padrão quando pressiono a tela. Mas, no meu projeto, o UITextFieldé somente leitura. Eu não preciso dessa funcionalidade. Por favor me diga como desabilitar este recurso.


3
coloque [UIMenuController sharedMenuController] .menuVisible = NO; in - (BOOL) canPerformAction: (SEL) ação withSender: (id) método do remetente.
— Ravoorinandan 01 de

Respostas:


108

A maneira mais fácil de desativar as operações da área de trabalho é criar uma subclasse de UITextViewque substitui o canPerformAction:withSender:método para retornar NOpara ações que você não deseja permitir:

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

Veja também UIResponder


1
@rpetrichm, eu usei sua solução, copiar / colar / cortar / selecionar / selecionar todas as opções estão desabilitadas, mas ainda está chegando Substituir ... | BIU | Definir opções. Quero desativar esse menu completo.
— Ameet Dhas

3
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }- para bloquear todas as opções
— Islam Q.

Isso é ótimo, no entanto, não sei como fazer isso para UISearchBar - como também há um campo de texto dentro, pensei que poderia sobrescrever o método de uma subclasse de UISearchBar, mas isso não funciona, infelizmente. Alguma ideia para isso?
— borchero

eu tenho muitos controles. como permitir copiar e colar apenas em um controle?
— Gaúcho

Isso não está funcionando para UITextView, embora eu tenha visto essa solução sugerida em vários lugares no SO. Alguém descobriu como fazer isso?
— Pigpocket

67

Subclasse UITextView e substitua canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
    return NO;
}

Observe que isso se aplica apenas a UITextViews não editáveis! Não testei em editáveis ​​...


Eu acho que return NO;no - (BOOL)canPerformAction:(SEL)action withSender:(id)sendermétodo é uma opção melhor.
— Islam Q.

29

Se desejar desativar cortar / copiar / colar em todos os UITextView seus aplicativos, você pode usar uma categoria com:

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

Ele salva uma subclasse ... :-)


3
você também pode colocar isso apenas em seu arquivo /, onde você precisa desse comportamento.
— markus_p

4
Isso só funciona como um efeito colateral e evita que o UITextViewcomporte-se conforme o esperado quando, por exemplo, é editável e recebe um toque. É muito para substituir canPerformAction:withSender:; é para isso que serve o protocolo.
— jdc

16
Você não pode substituir com segurança um método usando uma categoria. Este é um comportamento indefinido. Você deve subclassificar para substituir um método com segurança.
— Rob Napier,

2
Nota: Isso se aplica a todos os UITextViews em seu aplicativo. Não é ideal na maioria das vezes.
— bbrame de

2
Observe também que a Apple desaconselha isso : "Se o nome de um método declarado em uma categoria for o mesmo que um método na classe original, ou um método em outra categoria na mesma classe (ou mesmo uma superclasse), o comportamento é indefinido sobre qual método de implementação é usado em tempo de execução ... [e] pode causar problemas ao usar categorias para adicionar métodos às classes padrão Cocoa ou Cocoa Touch. "
— Rob

29

Esta foi a melhor solução de trabalho para mim:

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

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


3
bom, sem subclasses aqui!
— Martin Reichl

7
Eu amo a abordagem de fita adesiva e arame de enfardar aqui. Queria poder marcar você com +1 novamente :) Em vez disso, aqui está uma estrela dourada: i.imgur.com/EXLFt1Z.jpg
— jdc

22

A resposta @rpetrich funcionou para mim. Estou postando o código expandido, caso isso economize algum tempo.

No meu caso, não quero nenhum pop-up, mas quero que o UITextField seja capaz de se tornar o primeiro a responder.

Infelizmente, você ainda obtém o pop-up da lupa quando toca e segura o campo de texto.

@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
Por favor, poste uma versão rápida para isso também. obrigado.
— Salman Khakwani

@pinch: tnx. Ainda segura a água no iOS 12.1.3.
— YvesLeBorg

20

Se você não precisa de UITextView para rolar, a solução mais simples que não envolve subclassificação é simplesmente desativar a interação do usuário para a visualização de texto:

textField.userInteractionEnabled = NO;

2
Isso elimina o toque em links, etc. se for o que está na visualização de texto. Deve-se notar que esta não é uma boa solução para querer ocultar o selecionar / copiar / colar, mas também manter algum nível de interação habilitado.
— barfoon

3
Bem, eu teria pensado que isso seria óbvio.
— Luke Redpath

Estou usando campos de texto como rótulos para imagens em um jogo e não quero que a lupa apareça e não há razão para copiar o texto. Isso funciona muito bem para mim. Estou usando texto estilizado em um UIWebView e a mesma linha também funciona lá.
— JScarry

15

A maneira mais fácil é criar uma subclasse de UITextView que substitui 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;
}

Esta é a melhor solução para poder digitar texto, mas nada mais, e permite que toques no campo de texto não sejam mais "interceptados". Isso faz o que o OP queria e muito mais.
— hlfcoding

13

Quando eu retornar NÃO no canPerformAction no iOS 7, obtenho muitos erros como este:

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

Minha solução é a seguinte:

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

O truque é ocultar o controlador de menu no próximo ciclo na fila principal (logo depois de ser exibido).


muito bom. o único problema é que tenho 2 textviews e um textField e quero evitar o copiar e colar apenas nos campos textView. como identificar quem chamou o canPerformAction? a variável do remetente é o UIMenuController
— Gaúcho

1
Ele funciona na subclasse de UITextField (ou UITextView). Se você não usar a subclasse que criou, ela não terá nenhum efeito. Por exemplo, eu criei um TextFieldWithoutCopyPaste e usei onde não queria ter a funcionalidade de copiar e colar.
— Adam Wallner

bem, você está certo. Mas, no meu caso, o textView precisa da subclasse para usar canPerformAction e o textField precisa da subclasse para usar o textFieldDidBeginEditing a fim de animar a janela quando o teclado é mostrado. a animação move a janela com o teclado. Eu uso esse método para evitar que o teclado cubra o textField.
— Gaúcho

10

Esta é a maneira mais fácil de desativar todo o menu Selecionar / Copiar / Colar em um UITextView

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

Funciona para UITextField também. Obrigado por compartilhar.
— Gaurav Srivastava

1
Estou usando o código acima e ainda estou recebendo o menu como desativar isso, por favor me ajude.
— Bittoo

4

Desde o iOS 7, há uma propriedade no UITextView:

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

Isso impede que uma visualização permita seleções de texto. Funciona muito bem para mim.


4

Se você está procurando substituir o teclado por um, digamos, UIPickercomo inputView(com uma barra de ferramentas como um inputAccesotyView), então esta solução alternativa pode ajudar ...

  • Implemento textFieldShouldBeginEditing:
  • colocar dentro textField.userInteractionEnabled = NO;
  • Em seguida, quando estiver prestes a fechar o UIPickerView, defina-o como SIM.

Ao fazer isso, você seria capaz de tocar em UITextFielde mostrar as opções para escolher UIPickerView, neste momento você UITextField, de fato, não reagiria a qualquer evento de toque (isso inclui tocar e segurar para cortar, copiar e colar). No entanto, você deve se lembrar de defini-lo de volta para SIM quando estiver fechando o seu, UIPickerViewmas não será possível acessar o UIPickerViewnovamente.

O único momento em que falha é quando o usuário começa tocando e segurando o botão UITextView, então você verá cortar, copiar e colar novamente pela primeira vez. É por isso que você deve sempre validar suas entradas. É o mais fácil que consigo pensar. A outra opção era usar um UILabelpara texto somente leitura, mas você perde muitas funcionalidades do UITextView.


4

Subclasse UITextView - swift 4.0

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

Que estranho? ainda mostra a opção "Colar", mas não o faça se pressionado ...
— Fluxo do iOS de

4

Se você deseja desativar o pop-up para UITextField, tente este UITextFieldDelegatemétodo para alternar isUserInteractionEnabled.

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

3

Isso pode ser feito facilmente no storyboard (Xcode 6). Apenas desmarque Editable e Selectable no Attributes Inspector. Você ainda pode rolar a tela de texto.insira a descrição da imagem aqui


3

Isso funcionou para mim. Certifique-se de chamar resignFirstResponder no textView

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

2

Eu forneci uma resposta funcional aqui para desativar a seleção de texto + lupa, mantendo links clicáveis ​​habilitados Espero que ajude:

Depois de muito tempo tentando, consegui interromper a seleção de texto, ampliação e detecção de dados (links clicáveis ​​etc) substituindo addGestureRecognizer em uma subclasse UITextView permitindo apenas UILongPressGestureRecognizer atrasar o término do toque:

UIUnselectableTextView.m

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

2

Para Swift 3, ele foi alterado para:

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

2

Você pode corrigir isso em seu storyboard desmarcando estas caixas:

insira a descrição da imagem aqui

Ou você pode definir programaticamente assim:

textView.selectable = false
textView.editable = false

1

Eu fiz isso No meuUITextView , desativei a opção cortar, copiar, selecionar, etc. com muita facilidade.

Coloquei um UIViewno mesmo lugar onde havia colocado o UITextView, mas em self.viewe adicionei um touchDelegatemétodo como 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 funcionou para mim. Obrigado.


1

Rápido

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

Relacionados

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 você deseja adicionar uma opção personalizada ao seu UITextView, mas desabilitar as funções existentes, é assim que você faz no Swift 3 :

Para desativar a funcionalidade de copiar, colar e cortar, crie uma subclasse e substitua o seguinte:

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

No ViewController você tem seu CustomTextView e adiciona o seguinte para adicionar suas opções:

  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

Este método desabilitará completamente o menu Selecionar, Selecionar Tudo, Colar. Se você ainda conseguir alguma outra ação, basta adicioná-la à condição if como abaixo.

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

Você pode apenas criar uma categoria como esta:

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
Esta não é uma boa maneira de resolver o problema. Em primeiro lugar, isso afeta tudo, pois está na categoria. Em segundo lugar, usar objetos associados para uma tarefa bastante fácil pode causar mais problemas posteriormente com a depuração (por que funciona assim quando você esquece o que fez) do que dar lucro. É bom evitá-lo sempre que possível, na minha opinião. Torna o código menos fácil de localizar, depurar e entender por um novo programador no projeto.
— Vive de

0

Subclassificação UITextViewe substituição- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer é outra possibilidade de desabilitar ações indesejadas.

Use a classe do gestureRecognizerobjeto -para decidir se a ação deve ser adicionada ou não.


0

(SWIFT) Se você quiser apenas um campo de texto básico sem nenhuma das opções de menu ou lupa, crie uma subclasse de UITextField retornando false para gestoRecognizerShouldBegin:

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

        return false
    }
}

Isso irá ignorar toda a funcionalidade de toque no campo de texto, mas ainda permitirá que você use o teclado pop-up para adicionar / remover caracteres.

Se você estiver usando o storyboard, apenas atribua a classe recém-criada ao campo de texto ou se estiver criando um campo de texto programaticamente:

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

Para fazer isso, você precisa criar uma subclasse de seu UITextView e colocar este método.

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 tem duas propriedades que farão o que você precisa: isSelectable e isEditable .

Definindo isEditable como false, você evitará que o usuário edite o texto e definindo isSelectable como false, você evitará que o usuário selecione o texto dentro de seu textView, então isso impedirá que o menu de ação seja mostrado.


0

Encontre o código de amostra para referência:

 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

Use func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }no lugar de 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
    }
}

Crie uma nova classe com o nome StopPasteAction.swift

import UIKit

class StopPasteAction: UITextField {

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

Adicione a classe nova classe com seu TextField atual

insira a descrição da imagem aqui

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.