web-dev-qa-db-fra.com

Comment désactiver Copier, Couper, Sélectionner, Tout sélectionner dans UITextView

La fonctionnalité UITextView 'Copy, Cut, Select, Select All est affichée par défaut lorsque j'appuie sur l'écran. Mais, dans mon projet, la variable UITextField est uniquement en lecture seule. Je n'ai pas besoin de cette fonctionnalité. S'il vous plaît dites-moi comment désactiver cette fonctionnalité.

97
Aishwarya

Le moyen le plus simple de désactiver les opérations de collage est de créer une sous-classe de UITextView qui remplace la méthode canPerformAction:withSender: pour renvoyer NO pour les actions que vous ne souhaitez pas autoriser:

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

Voir aussi UIResponder

95
rpetrich

Sous-classe UITextView et écraser canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
    return NO;
}

Notez que cela ne s'applique que pour les UITextViews non modifiables! Je ne l'ai pas testé sur ceux qui peuvent être édités ...

67
iCoder

Si vous souhaitez désactiver couper/copier/coller sur all UITextView de votre application, vous pouvez utiliser une category avec:

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

Cela économise un sous-classement ... :-)

30
Damien Debin

Ce fut la meilleure solution de travail pour moi:

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

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

29
Saraiva Alcides

Si vous n'avez pas besoin de UITextView pour faire défiler l'écran, la solution la plus simple n'impliquant pas de sous-classification consiste simplement à désactiver l'interaction utilisateur pour la vue texte:

textField.userInteractionEnabled = NO;
21
Luke Redpath

@rpetrich answer a travaillé pour moi. Je publie le code développé au cas où cela ferait gagner du temps à quelqu'un.

Dans mon cas, je ne veux aucune fenêtre contextuelle, mais je veux que UITextField puisse devenir le premier répondant.

Malheureusement, vous obtenez toujours le menu contextuel de la loupe lorsque vous maintenez le doigt appuyé sur le champ de texte.

@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)
    }

}
15
pinch

Le moyen le plus simple est de créer une sous-classe de UITextView qui remplace le canPerformAction 

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

Lorsque je retourne NON dans canPerformAction sur iOS 7, je vais recevoir de nombreuses erreurs comme celle-ci:

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

Ma solution est la suivante:

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

L'astuce consiste à masquer le contrôleur de menu lors du prochain cycle de la file d'attente principale (juste après son affichage).

13
Adam Wallner

C’est le moyen le plus simple de désactiver tout le menu Sélectionner/Copier/Coller dans un UITextView.

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

Depuis iOS 7, il existe une propriété sur UITextView:

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

Cela empêche une vue de permettre les sélections de texte. Ça marche bien pour moi.

4
Epaga

Si vous cherchez à remplacer le clavier par, disons, UIPicker en tant que inputView (avec bien sûr une barre d’outils en tant que inputAccesotyView), cette solution de contournement pourrait vous aider ...

  • Implémenter textFieldShouldBeginEditing:
  • textField.userInteractionEnabled = NO; à l'intérieur
  • Ensuite, lorsque vous êtes sur le point de fermer la UIPickerView, définissez-la sur YES.

En faisant cela, vous pourrez taper sur la variable UITextField et afficher les options de choix à partir de la variable UIPickerView; à ce moment-là, votre UITextField ne pourra en fait réagir à aucun événement tactile coller). Cependant, vous devez vous rappeler de le redéfinir sur OUI lorsque vous fermez votre UIPickerView. Cependant, vous ne pourrez plus accéder à votre UIPickerView.

Le seul moment où cela échoue est le moment où l'utilisateur commence à taper sur la variable UITextView et à la maintenir enfoncée. Vous verrez alors copier-coller pour la première fois. C'est pourquoi vous devez toujours valider vos entrées. C'est le plus facile que je puisse penser. L'autre option consistait à utiliser un UILabel pour le texte en lecture seule, mais vous manquiez de nombreuses fonctionnalités intéressantes de UITextView.

4
rn3sto

Sous-classe UITextView - Swift 4.0

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

Cela peut être fait facilement dans le storyboard (Xcode 6). Décochez simplement Editable et Selectable dans l'inspecteur d'attributs. Vous pouvez toujours faire défiler la vue du texte.  enter image description here

2
Hari Kunwar

Cela a fonctionné pour moi. Assurez-vous d'appeler resignFirstResponder sur le textView

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

J'ai fourni une réponse de travail ici pour désactiver la sélection de texte + loupe, en conservant les liens activables activés J'espère que cela vous aidera:

Après avoir longuement essayé, j'ai réussi à arrêter la sélection du texte, à agrandir et à garder la détection des données (liens cliquables, etc.) en remplaçant addGestureRecognizer dans une sous-classe UITextView, permettant uniquement à UILongPressGestureRecognizer de retarder la fin du toucher:

UIUnselectableTextView.m

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

Pour Swift 3 il a été remplacé par:

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

Je l'ai fait. Sur ma UITextView, j'ai très facilement désactivé l’option Couper, Copier, Sélectionner, etc.

J'ai placé une UIView au même endroit que j'avais placé la UITextView, mais sur self.view et ajouté une méthode touchDelegate comme suit:

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

    }
}

et cela a fonctionné pour moi. Je vous remercie.

1
user207221

Vous pouvez résoudre ce problème dans votre scénario en décochant les cases suivantes:

 enter image description here

Ou vous pouvez définir par programme comme suit:

textView.selectable = false
textView.editable = false
1
Khuong

Rapide

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

En relation

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
Suragch

Cette méthode désactive complètement le menu Sélectionner, Sélectionner tout, Coller. Si vous obtenez toujours une autre action, ajoutez simplement cela à la condition if comme ci-dessous.

- (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];
    }
1
Sivrish Thangamani

Si vous voulez désactiver la popup pour UITextField, essayez cette méthode UITextFieldDelegate pour basculer isUserInteractionEnabled.

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    textField.isUserInteractionEnabled = false
    return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    textField.isUserInteractionEnabled = true
    return true
}
0
Jayesh Thanki
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
Nirav Ghori

Si vous souhaitez ajouter une option personnalisée à votre UITextView mais désactiver les fonctions existantes, procédez comme suit: Swift 3 :

Pour désactiver la fonctionnalité copier, coller, couper, créez une sous-classe et remplacez les éléments suivants: 

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

Sur le ViewController, votre CustomTextView ajoute ce qui suit pour ajouter vos options: 

  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)")

    }
0
Sam Bing

Swift 3

Pour ce faire, vous devez sous-classer votre UITextView et mettre cette méthode.

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
Zaldy

UITextView a deux propriétés qui feront ce dont vous avez besoin: isSelectable et isEditable.

Si vous définissez isEditable sur false, vous évitez que l'utilisateur modifie le texte. Si vous définissez isSelectable sur false, vous évitez que l'utilisateur sélectionne du texte dans votre textView, ce qui empêche l'affichage du menu Action.

0
L. Davì

(Swift) Si vous souhaitez uniquement un champ de texte de base sans option de menu ni loupe, créez une sous-classe de UITextField renvoyant la valeur false à gestureRecognizerShouldBegin:

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

        return false
    }
}

Cela contournera toutes les fonctionnalités tactiles du champ de texte tout en vous permettant d'utiliser le clavier contextuel pour ajouter/supprimer des caractères.

Si vous utilisez le storyboard, affectez simplement la classe nouvellement créée au champ de texte ou si vous créez un champ de texte par programme:

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

basic.becomeFirstResponder()
0
Krivvenz

Le sous-classement UITextView et la substitution de - (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer constituent une autre possibilité de désactiver les actions indésirables.

Utilisez la classe de l'objet gestureRecognizer- pour décider si l'action doit être ajoutée ou non.

0
RhodanV5500

Vous pouvez simplement créer une catégorie comme celle-ci:

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
0
user2091319