Comment désactiver l'édition UITextField tout en acceptant le toucher?

107

Je fais un UITextFieldqui a un UIPickerViewas inputView. Tout va bien, sauf que je peux éditer par copier, coller, couper et sélectionner du texte, et je ne le veux pas. Seul le sélecteur doit modifier le champ de texte.

J'ai appris que je peux désactiver l'édition en réglant setEnabledou setUserInteractionEnableden NO. Ok, mais le TextField cesse de répondre au toucher et le sélecteur ne s'affiche pas.

Que puis-je faire pour y parvenir?

Luiz de Prá
la source

Réponses:

131

En utilisant le délégué textfield, il existe une méthode

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

Renvoyez NON à partir de cela et toute tentative de l'utilisateur de modifier le texte sera rejetée.

De cette façon, vous pouvez laisser le champ activé tout en empêchant les personnes d'y coller du texte.

Nick Lockwood
la source
4
Si vous souhaitez toujours répondre au toucher, répondez à "toucher vers le bas" et non "toucher vers le bas". Sinon, votre événement n'est jamais appelé.
radven
@NickLockwood existe-t-il des moyens de permettre à textField de devenir le premier répondeur, mais de désactiver l'interaction de l'utilisateur et de masquer le curseur?
onmyway133
1
@entropy Je suppose que vous voulez pouvoir sélectionner le contenu afin que l'utilisateur puisse le copier? Si vous sous-classez UITextField, vous pouvez remplacer à peu près n'importe quel comportement - par exemple, vous pouvez forcer le champ à toujours tout sélectionner chaque fois que l'utilisateur touche est, ce qui masquerait effectivement le curseur.
Nick Lockwood
1
@LoryLory c'est la même chose, utilisez simplement la syntaxe Swift pour la méthode déléguée à la place.
Nick Lockwood
5
Plus précisément, nous pouvons utiliser "textFieldShouldBeginEditing" si nécessaire
Naveen Shan
22

Traduisez la réponse de Nick en rapide:

P / S: Retourne false => les champs de texte ne peuvent pas être saisis, éditez au clavier Il peut juste définir le texte par code.EX: textField.text = "Ma chaîne ici"

override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return false
}
Lee
la source
3
Cela ne fonctionne pas pour moi. Cliquez simplement longuement sur le champ de texte jusqu'à ce que le zoom apparaisse et que le menu couper / copier / coller iOS apparaisse et je peux l'utiliser pour modifier le texte.
RowanPD
2
swift 4: `func textField (_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {return false}`
lionello
16

Ce serait le plus simple de tous:

in viewDidLoad: (définissez le délégué uniquement pour les champs de texte qui ne doivent pas être modifiables.

self.textfield.delegate=self;

et insérez cette fonction déléguée:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
return NO;
}

C'est tout!

Ankish Jain
la source
27
Cela empêche le sélecteur d'être présenté et ne résout donc pas le problème décrit
Martin Lockett
6
@MartinLockett Si vous déclenchez le UIPickerViewcomportement à partir de cette méthode déléguée, cela fonctionne bien.
Albert Bori
9

Dans Swift 3+:

class MyViewController: UIViewController, UITextFieldDelegate {

   override func viewDidLoad() {
      self.myTextField.delegate     = self
   }

   func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
      if textField == myTextField {
         // code which you want to execute when the user touch myTextField
      }
      return false
   }
}
Nadeesha Lakmal
la source
7

Il serait plus élégant de créer une sous-classe personnalisée de UITextFieldce retour NOpour tous les appels à canPerformAction:withSender:(ou au moins où actionest @selector(cut)ou @selector(paste)), comme décrit ici .

De plus, j'implémenterais également - (BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString *) string selon la suggestion de Nick afin de désactiver la saisie de texte à partir des claviers Bluetooth.

MrMage
la source
Je ne peux pas pour la vie de moi savoir comment faire ça. La sous-classe canPerformActionet les shouldChangeCharactersInRangeméthodes ne sont jamais appelées.
Nestor
7

Placez simplement un UIButton exactement sur tout le UITextField sans Label-text, ce qui le rend "invisible". Ce bouton peut recevoir et déléguer des touches à la place du Textfield et le contenu du TextField est toujours visible.

Timm Kent
la source
7

Dans Swift:

func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
    questionField.resignFirstResponder();
    // Additional code here
    return false
}
Saranya
la source
3

J'ai utilisé la solution fournie par MrMage. La seule chose que j'ajouterais est que vous devriez démissionner de l'UITextView en tant que premier répondeur, sinon vous êtes coincé avec le texte sélectionné.

Voici mon code SWIFT:

class TouchableTextView : UITextView {

    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        self.resignFirstResponder()
        return false
    }

    override func shouldChangeTextInRange(range: UITextRange, replacementText text: String) -> Bool {
        self.resignFirstResponder()
        return false
    }

}
Leedrick
la source
1

Pour une alternative qui gère l'UIPickerView et les feuilles d'action, consultez ActionSheetPicker

https://github.com/TimCinel/ActionSheetPicker

Ce sont les cocoapodes activés. Il gère tous les boutons d'annulation et de fin de la feuille d'action. Les exemples dans l'exemple de projet sont excellents. Je choisis ActionSheetStringPicker, qui gère facilement uniquement les options basées sur des chaînes, mais l'API peut gérer presque tout ce que je peux penser.

À l'origine, j'ai lancé une solution similaire à la réponse cochée, mais je suis tombé sur ce projet et il m'a fallu environ 20 minutes pour intégrer les choses dans mon application pour une utilisation, y compris l'utilisation de cocopods: ActionSheetPicker (~> 0.0)

J'espère que cela t'aides.

Téléchargez le projet git et regardez les classes suivantes:

  • ActionSheetPickerViewController.m
  • ActionSheetPickerCustomPickerDelegate.h

Voici à peu près la plupart du code que j'ai ajouté, plus les importations * .h.

- (IBAction)gymTouched:(id)sender {
      NSLog(@"gym touched");

      [ActionSheetStringPicker showPickerWithTitle:@"Select a Gym" rows:self.locations initialSelection:self.selectedIndex target:self successAction:@selector(gymWasSelected:element:) cancelAction:@selector(actionPickerCancelled:) origin:sender];
 }


- (void)actionPickerCancelled:(id)sender {
    NSLog(@"Delegate has been informed that ActionSheetPicker was cancelled");
}


- (void)gymWasSelected:(NSNumber *)selectedIndex element:(id)element {
    self.selectedIndex = [selectedIndex intValue];

    //may have originated from textField or barButtonItem, use an IBOutlet instead of element
    self.txtGym.text = [self.locations objectAtIndex:self.selectedIndex];
}


-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    return NO;  // Hide both keyboard and blinking cursor.
}
Nick N
la source
Une version mise à jour du pod est ici. github.com/skywinder/ActionSheetPicker-3.0
Nick N
1

Pour empêcher la modification de UITextField lors de l'utilisation de UIPickerView pour sélectionner des valeurs (dans Swift):

self.txtTransDate = self.makeTextField(self.transDate, placeHolder: "Specify Date")
self.txtTransDate?.addTarget(self, action: "txtTransDateEditing:", forControlEvents: UIControlEvents.EditingDidBegin)

func makeTextField(text: String?, placeHolder: String) -> UITextField {
    var textField = UITextField(frame: CGRect(x: 140, y: 0, width: 220.00, height: 40.00));
    textField.placeholder = placeHolder
    textField.text = text
    textField.borderStyle = UITextBorderStyle.Line
    textField.secureTextEntry = false;
    textField.delegate = self
    return textField
}


func txtTransDateEditing(sender: UITextField) {
    var datePickerView:UIDatePicker = UIDatePicker()
    datePickerView.datePickerMode = UIDatePickerMode.Date
    sender.inputView = datePickerView
    datePickerView.addTarget(self, action: Selector("datePickerValueChanged:"), forControlEvents: UIControlEvents.ValueChanged)
}

func datePickerValueChanged(sender: UIDatePicker) {
    var dateformatter = NSDateFormatter()
    dateformatter.dateStyle = NSDateFormatterStyle.MediumStyle
    self.txtTransDate!.text = dateformatter.stringFromDate(sender.date)
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool  {
    self.resignFirstResponder()
    return false
}
Thiru
la source
0

Cette solution de contournement fonctionne. Placez un UIView transparent au-dessus du champ de texte et implémentez le code suivant:

- (void)viewDidLoad
{
 [super viewDidLoad];

   UILongPressGestureRecognizer *press = [[UILongPressGestureRecognizer alloc]             initWithTarget:self action:@selector(longPress)];
[transparentView addGestureRecognizer:press];
 [press release];
  press = nil;
}

-(void)longPress
{
   txtField.userInteractionEnabled = NO;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   txtField.userInteractionEnabled = YES;
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
  [txtField becomeFirstResponder];
}
cocoakomali
la source
1
Je ne comprends pas pourquoi vous n'utilisez pas un simple UIButton + touchUpInside transparent, et j'ai opté pour le geste UIView + à la place.
Chen Li Yong
0

Faites que votre inputView soit présenté par un champ de texte caché qui modifie également le texte de celui présenté et désactivé.

Sandro Vezzali
la source
0

Je ne sais pas à quel point c'est piraté, mais la seule chose qui a fait l'affaire dans mon cas a été d'ajouter une action cible et d'appeler endEditing. Étant donné que mon sélecteur contrôle ma valeur UITextField.text, je pourrais ignorer le clavier dès que l'utilisateur clique sur le champ. Voici un code:

uiTextFieldVariable.addTarget(self, action: #selector(dismissKeyboard), for: .editingDidBegin)

@objc private func dismissKeyboard() {
    endEditing(true)
}
Bruno Myrrha
la source
-5

J'ai utilisé :

[self.textField setEnabled:NO];

et son travail bien

Chris
la source
-7

Cela a fonctionné pour moi [textview setEditable:NO]; Les réponses ci-dessus compliquent trop la situation.

Tolgab
la source
1
L'OP a écrit "J'ai appris que je peux désactiver l'édition en définissant setEnabled ou setUserInteractionEnabled: NO à NO. Ok, mais le TextField cesse de répondre au toucher et le sélecteur n'apparaît pas." Votre réponse arrêtera tous les événements, ce qui n'était pas le résultat souhaité.
maninvan
@Tolgab n'est pas la solution même liée pour cet OP!
Anurag Sharma