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é.
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
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 ...
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 ... :-)
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
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;
@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)
}
}
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;
}
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).
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;
}
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.
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 ...
textFieldShouldBeginEditing:
textField.userInteractionEnabled = NO;
à l'intérieurUIPickerView
, 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
.
Sous-classe UITextView - Swift 4.0
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
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;
}
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];
}
}
Pour Swift 3 il a été remplacé par:
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
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.
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.
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];
}
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
}
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)}
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)")
}
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)
}
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.
(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()
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.
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