UITextField secureTextEntry: funciona de SÍ a NO, pero el cambio a SÍ no tiene efecto
uitextfielddelegate (5)
Con iOS, nunca debe tratar de "piratear" cosas, si el marco no proporciona el comportamiento que desea, ¡cambie de opinión!
Primero es más fácil ^^, en segundo lugar, el usuario no responderá a esto, entonces nunca se sabe si la próxima actualización de iOS lo romperá o no, por lo que puede ser peligroso para su aplicación.
"¿Quieres que el usuario vea la contraseña que está grabando en un campo de texto seguro", puedes mostrar un UILabel en la parte inferior? ¿O un cuadro de alerta de confirmación con la contraseña clara?
Lo anterior lo dice todo: tengo un UITextField configurado para asegurar, pero quiero darles a los usuarios la opción de hacerlo no seguro (para que puedan ver con seguridad lo que escribieron si están en un área privada). Sin embargo, supongamos que presionan el interruptor por error y quieren cambiarlo de nuevo al modo seguro. Eso no funciona. Lo he intentado todo: utilizar -1 en lugar de SÍ, eliminar el texto y luego volver a colocarlo. Estoy en una pérdida total en otras ideas. [Ingresó rdar: // 9781908]
EDITAR: Creo que este problema está solucionado a partir de iOS5.
Debe ser un problema de enfoque de entrada: cuando está enfocado, UITextField solo puede cambiar ENCENDIDO-> APAGADO.
Prueba el siguiente truco para apagar-> ON:
textField.enabled = NO;
textField.secureTextEntry = YES;
textField.enabled = YES;
[textField becomeFirstResponder];
EDIT (dhoerl): En iOS 9.3, encontré que esto funciona, pero hay un problema. Si ingresa, digamos 3 caracteres a la vista, luego cambie a texto seguro, luego escriba un carácter, los 3 caracteres preexistentes desaparecerán. Intenté todo tipo de trucos para borrar, luego reinicié el texto sin éxito. Finalmente intenté simplemente jugar con el control cortando y pegando; pegar en el modo recién cambiado a modo seguro funcionó muy bien. Así que lo emulé en código, y ahora todo funciona bien, tampoco es necesario jugar con el respondedor. Esto es lo que finalmente terminé con:
if textview should go into secure mode and the textfield is not empty {
textField.text = ""
textField.secureTextEntry = true
UIPasteboard.generalPasteboard().string = password
textField.paste(self)
UIPasteboard.generalPasteboard().string = ""
}
Preferiría no tener que hacer este pegado, pero si lo quieres sin problemas, esta es la única forma que puedo encontrar para hacerlo.
Entré a rdar contra este problema, pero encontré una solución. Esencialmente tienes que reemplazar el control "atascado" por uno nuevo mediante programación. Lo más fácil es archivar el control existente en viewDidLoad y luego desarchivar según sea necesario:
// do in viewDidLoad
self.passwordMemberArchive = [NSMutableData data];
NSKeyedArchiver *ka = [[NSKeyedArchiver alloc] initForWritingWithMutableData:passwordMemberArchive];
[ka encodeObject:password];
[ka finishEncoding];
[ka release];
// In the action method when you get the UISwitch action message ---
// when your switch changes state
if(isOn) {
NSString *text = [NSString stringWithString:password.text];
NSKeyedUnarchiver *kua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
UITextField *tf = [kua decodeObject];
[kua finishDecoding];
[kua release];
tf.inputAccessoryView = textField.inputAccessoryView;
tf.frame = textField.frame;
BOOL isFirstResponder = [textField isFirstResponder];
[scrollView insertSubview:tf aboveSubview:textField];
if(isFirstResponder) {
[tf becomeFirstResponder];
}
[textField removeFromSuperview];
self.password = tf;
if([text length]) {
if(isFirstResponder) {
// http://.com/questions/1317929/insert-string-at-cursor-position-of-uitextfield
// Get a reference to the system pasteboard
UIPasteboard* lPasteBoard = [UIPasteboard generalPasteboard];
// Save the current pasteboard contents so we can restore them later
NSArray* lPasteBoardItems = [lPasteBoard.items copy];
// Update the system pasteboard with my string
lPasteBoard.string = text;
// Paste the pasteboard contents at current cursor location
[tf paste:self];
// Restore original pasteboard contents
lPasteBoard.items = lPasteBoardItems;
[lPasteBoardItems release];
} else {
tf.text = text;
}
}
} else {
textField.secureTextEntry = NO;
}
La solución de Mike R es buena, pero prefiero este enfoque:
BOOL wasFirstResponder;
if ((wasFirstResponder = [passwordField isFirstResponder])) {
[passwordField resignFirstResponder];
}
// In this example, there is a "show password" toggle
[passwordField setSecureTextEntry:![passwordField isSecureTextEntry]];
if (wasFirstResponder) {
[passwordField becomeFirstResponder];
}
De esa manera solo volverás a ser el Primer Contestador cuando sea necesario.
Versión rápida de la solución de Sandy.
if #available(iOS 9.2, *) {
passwordTextField.secureTextEntry = !passwordTextField.secureTextEntry
}
else {
let wasFirstResponder = passwordTextField.isFirstResponder()
if wasFirstResponder {
passwordTextField.resignFirstResponder()
}
passwordTextField.secureTextEntry = !passwordTextField.secureTextEntry
if wasFirstResponder {
passwordTextField.becomeFirstResponder()
}
}