Come disabilitare la modifica di UITextField ma accettare comunque il tocco?


107

Sto facendo un UITextFieldche ha un UIPickerViewas inputView. Va tutto bene, tranne per il fatto che posso modificare copia, incolla, taglia e seleziona il testo e non lo voglio. Solo il Selettore dovrebbe modificare il campo di testo.

Ho imparato che posso disabilitare la modifica impostando setEnabledo setUserInteractionEnabledsu NO. Ok, ma TextField smette di rispondere al tocco e il selettore non viene visualizzato.

Cosa posso fare per ottenerlo?

Risposte:


131

Usando il delegato del campo di testo, c'è un metodo

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

Restituisci NO da questo e qualsiasi tentativo da parte dell'utente di modificare il testo verrà rifiutato.

In questo modo puoi lasciare il campo abilitato ma impedire comunque alle persone di incollare del testo al suo interno.


4
Se vuoi comunque rispondere al tocco, rispondi a "touch down" e non a "touch up inside". Altrimenti il ​​tuo evento non verrà mai chiamato.
radven

@ NickLockwood ci sono modi in cui possiamo ancora consentire al textField di diventare il primo risponditore, ma disabilitare l'interazione dell'utente e nascondere il cursore?
onmyway133

1
@entropy Suppongo che tu voglia essere in grado di selezionare il contenuto in modo che l'utente possa copiarlo? Se si sottoclasse UITextField è possibile sovrascrivere praticamente qualsiasi comportamento, ad esempio è possibile forzare il campo a selezionare sempre tutto ogni volta che l'utente tocca is, il che nasconderebbe effettivamente il cursore.
Nick Lockwood,

1
@LoryLory è lo stesso, usa invece la sintassi Swift per il metodo delegato.
Nick Lockwood

5
Più precisamente possiamo usare "textFieldShouldBeginEditing" se necessario
Naveen Shan,

22

Traduci la risposta di Nick in swift:

P / S: Return false => i campi di testo non possono essere inseriti, modificare dalla tastiera. Può semplicemente impostare il testo tramite codice.EX: textField.text = "My String Here"

override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return false
}

3
Questo non funziona per me. Fai clic a lungo sul campo di testo finché non viene visualizzato lo zoom e viene visualizzato il menu taglia / copia / incolla di iOS e posso usarlo per modificare il testo.
RowanPD

2
swift 4: `func textField (_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {return false}`
lionello

16

Questo sarebbe il più semplice di tutti:

in viewDidLoad: (imposta il delegato solo per i campi di testo che non dovrebbero essere modificabili.

self.textfield.delegate=self;

e inserisci questa funzione delegato:

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

Questo è tutto!


27
Ciò impedisce la presentazione del selettore e quindi non risolve il problema descritto
Martin Lockett

6
@MartinLockett Se attivi il UIPickerViewcomportamento da quel metodo delegato, funziona bene.
Albert Bori

9

In 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
   }
}

7

Sarebbe più elegante per creare una sottoclasse personalizzata di UITextFieldche restituisce NOper tutte le chiamate a canPerformAction:withSender:(o almeno dove actionè @selector(cut)o @selector(paste)), come descritto qui .

Inoltre, implementerei anche - (BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString *) stringa secondo il suggerimento di Nick per disabilitare l'immissione di testo dalle tastiere Bluetooth.


Non posso per la vita di me capire come farlo. I metodi canPerformActione le sottoclassi shouldChangeCharactersInRangenon vengono mai chiamati.
Nestor

7

Posiziona semplicemente un UIButton esattamente sull'intero UITextField senza il testo dell'etichetta che lo rende "invisibile". Questo pulsante può ricevere e delegare tocchi invece del Textfield e il contenuto del TextField è ancora visibile.


7

In Swift:

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

3

Ho usato la soluzione fornita da MrMage. L'unica cosa che aggiungerei è che dovresti dimettere UITextView come primo risponditore, altrimenti sei bloccato con il testo selezionato.

Ecco il mio codice 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
    }

}

1

Per un'alternativa che gestisce UIPickerView e Action Sheets, controlla ActionSheetPicker

https://github.com/TimCinel/ActionSheetPicker

È abilitato per cocoapods. Gestisce tutti i pulsanti Annulla e Fine sul foglio delle azioni. Gli esempi all'interno del progetto di esempio sono fantastici. Scelgo ActionSheetStringPicker, che gestisce facilmente solo le opzioni basate su String, ma l'API può gestire quasi tutto ciò che mi viene in mente.

Inizialmente ho avviato una soluzione molto simile alla risposta contrassegnata da un segno di spunta, ma sono incappato in questo progetto e mi ci sono voluti circa 20 minuti per integrare le cose nella mia app per l'utilizzo, incluso l'uso di cocopods: ActionSheetPicker (~> 0,0)

Spero che questo ti aiuti.

Scarica il progetto git e guarda le seguenti classi:

  • ActionSheetPickerViewController.m
  • ActionSheetPickerCustomPickerDelegate.h

Ecco all'incirca la maggior parte del codice che ho aggiunto, oltre alle importazioni * .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.
}

Una versione aggiornata del pod è qui. github.com/skywinder/ActionSheetPicker-3.0
Nick N

1

Per impedire la modifica di UITextField durante l'utilizzo di UIPickerView per la selezione dei valori (in 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
}

0

Questa soluzione alternativa funziona. Metti una UIView trasparente sopra il campo di testo e implementa il codice seguente:

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

1
Sono confuso sul motivo per cui non usi un semplice pulsante UIB trasparente + touchUpInside e ho optato invece per il gesto UIView +.
Chen Li Yong

0

Fai in modo che il tuo inputView sia presentato da un campo di testo nascosto che cambia anche il testo di quello presentato e disabilitato.


-5

Ero solito :

[self.textField setEnabled:NO];

e il suo lavoro va bene


-7

Questo ha funzionato per me [textview setEditable:NO]; Le risposte di cui sopra stanno complicando eccessivamente la situazione.


1
L'OP ha scritto "Ho imparato che posso disabilitare la modifica impostando setEnabled o setUserInteractionEnabled: NO su NO. Ok, ma TextField smette di rispondere al tocco e il selettore non viene visualizzato." La tua risposta interromperà tutti gli eventi, che non erano il risultato desiderato.
Maninvan

@ Tolgab non è nemmeno la soluzione correlata per questo OP!
Anurag Sharma
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.