¿Cómo deshabilitar la edición de UITextField pero aún aceptar el toque?


107

Estoy haciendo un UITextFieldque tiene un UIPickerViewas inputView. Está todo bien, excepto que puedo editar copiando, pegando, cortando y seleccionando texto, y no lo quiero. Solo el selector debe modificar el campo de texto.

Aprendí que puedo deshabilitar la edición configurando setEnabledo setUserInteractionEnabledpara NO. Ok, pero TextField deja de responder al tacto y el selector no aparece.

¿Qué puedo hacer para lograrlo?

Respuestas:


131

Usando el delegado de campo de texto, hay un método

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

Devuelva NO de esto, y cualquier intento por parte del usuario de editar el texto será rechazado.

De esa manera, puede dejar el campo habilitado pero aún evitar que las personas peguen texto en él.


4
Si aún desea responder al tacto, responda "tocar hacia abajo" y no "retocar por dentro". De lo contrario, su evento nunca se llamará.
radven

@NickLockwood, ¿hay alguna forma en que podamos permitir que textField se convierta en el primer respondedor, pero deshabilite la interacción del usuario y oculte el signo de intercalación?
onmyway133

1
@entropy Supongo que desea poder seleccionar el contenido para que el usuario pueda copiarlo. Si crea una subclase de UITextField, puede anular prácticamente cualquier comportamiento; por ejemplo, podría obligar al campo a seleccionar siempre todo cuando el usuario toque, lo que ocultaría efectivamente el símbolo de intercalación.
Nick Lockwood

1
@LoryLory es lo mismo, solo use la sintaxis Swift para el método delegado en su lugar.
Nick Lockwood

5
Más precisamente, podemos usar "textFieldShouldBeginEditing" si es necesario
Naveen Shan

22

Traduce la respuesta de Nick a rápido:

P / S: Devuelve falso => ​​los campos de texto no se pueden ingresar, editar con el teclado. Solo puede establecer texto por código.EX: textField.text = "My String Here"

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

3
Esto no me funciona. Simplemente haga clic prolongadamente en el campo de texto hasta que aparezca el zoom y aparezca el menú de cortar / copiar / pegar de iOS y pueda usarlo para modificar el texto.
RowanPD

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

16

Este sería el más simple de todos:

en viewDidLoad: (establezca el delegado solo para campos de texto que no deberían ser editables.

self.textfield.delegate=self;

e inserte esta función de delegado:

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

¡Eso es!


27
Esto evita que se presente el selector y, por lo tanto, no soluciona el problema descrito
Martin Lockett

6
@MartinLockett Si activa el UIPickerViewcomportamiento de ese método delegado, funciona bien.
Albert Bori

9

En 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

Sería más elegante crear una subclase personalizada UITextFieldque devuelva NOpara todas las llamadas a canPerformAction:withSender:(o al menos donde actionestá @selector(cut)o @selector(paste)), como se describe aquí .

Además, también implementaría - (BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString *) cadena según la sugerencia de Nick para deshabilitar la entrada de texto desde teclados Bluetooth.


No puedo por mi vida averiguar cómo hacer eso. Los métodos canPerformActiony de la subclase shouldChangeCharactersInRangenunca se llaman.
Nestor

7

Simplemente coloque un UIButton exactamente sobre todo el UITextField sin etiqueta-texto que lo haga "invisible". Este botón puede recibir y delegar toques en lugar del campo de texto y el contenido del campo de texto sigue siendo visible.


7

En Swift:

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

3

Usé la solución proporcionada por MrMage. Lo único que agregaría es que debe renunciar a UITextView como primer respondedor, de lo contrario, se quedará atascado con el texto seleccionado.

Aquí está mi código rápido:

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

Para una alternativa que maneja UIPickerView y Action Sheets, consulte ActionSheetPicker

https://github.com/TimCinel/ActionSheetPicker

Tiene cocoapods habilitados. Maneja todos los botones cancelar y listo en la hoja de acción. Los ejemplos dentro del proyecto de muestra son geniales. Elijo ActionSheetStringPicker, que maneja fácilmente solo las opciones basadas en cadenas, pero la API puede manejar casi cualquier cosa que se me ocurra.

Originalmente comencé una solución muy parecida a la respuesta marcada, pero tropecé con este proyecto y me tomó aproximadamente 20 minutos integrar las cosas en mi aplicación para su uso, incluido el uso de cocopods: ActionSheetPicker (~> 0.0)

Espero que esto ayude.

Descarga el proyecto git y mira las siguientes clases:

  • ActionSheetPickerViewController.m
  • ActionSheetPickerCustomPickerDelegate.h

Aquí está aproximadamente la mayor parte del código que agregué, más las importaciones * .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.
}

Aquí hay una versión actualizada del pod. github.com/skywinder/ActionSheetPicker-3.0
Nick N

1

Para evitar la edición de UITextField mientras usa UIPickerView para seleccionar valores (en 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

Esta solución funciona. Coloque una UIView transparente encima del campo de texto e implemente el siguiente código:

- (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
Estoy confundido de por qué no usa un simple UIButton + touchUpInside transparente y optó por UIView + gesto en su lugar.
Chen Li Yong

0

Haga que su inputView sea presentado por un campo de texto oculto que también cambie el texto del presentado y deshabilitado.


-5

Solía ​​:

[self.textField setEnabled:NO];

y funciona bien


-7

Esto funcionó para mí [textview setEditable:NO]; Las respuestas anteriores complican demasiado la situación.


1
El OP escribió "Aprendí que puedo deshabilitar la edición configurando setEnabled o setUserInteractionEnabled: NO a NO. Ok, pero TextField deja de responder al tacto y el selector no aparece". Su respuesta detendrá todos los eventos, lo que no fue el resultado deseado.
maninvan

¡@Tolgab ni siquiera es la solución relacionada para este OP!
Anurag Sharma
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.