web-dev-qa-db-fra.com

UITextField secureTextEntry - fonctionne de OUI à NON, mais revenir à OUI n'a aucun effet

Ce qui précède dit tout. J'ai un ensemble UITextField à sécuriser, mais je veux donner aux utilisateurs la possibilité de le rendre non sécurisé (afin qu'ils puissent voir avec certitude ce qu'ils ont tapé s'ils se trouvent dans une zone privée). Cependant, supposons qu'ils aient appuyé sur la bascule par erreur et qu'ils souhaitent revenir au mode sécurisé? Cela ne fonctionne pas. J'ai tout essayé - en utilisant -1 au lieu de YES, en supprimant le texte, puis en le remettant en place. Je suis complètement perdu sur d'autres idées. [Entré rdar: // 9781908]

EDIT: Je crois que ce problème est corrigé à partir de iOS5.

27
David H

Ce doit être un problème d’entrée-focus: une fois focalisé, UITextField ne peut changer que ON-> OFF.
Essayez le prochain truc pour éteindre -> allumer:

textField.enabled = NO;
textField.secureTextEntry = YES;
textField.enabled = YES;
[textField becomeFirstResponder];

EDIT (dhoerl): Dans iOS 9.3, j'ai trouvé que cela fonctionne mais il y a un problème. Si vous entrez 3 caractères en clair, passez en texte sécurisé, puis tapez un caractère, les 3 caractères préexistants disparaissent. J'ai essayé toutes sortes d'astuces pour effacer, puis réinitialiser le texte sans succès. J'ai finalement essayé de jouer avec le contrôle en effectuant des copier-coller - coller dans le mode nouvellement basculé vers le mode sécurisé a fonctionné à merveille. Donc, je l'ai imité dans le code, et maintenant tout fonctionne bien - pas besoin de jouer avec le répondeur non plus. Voici ce que j'ai finalement fini avec:

    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 = ""
    }

Je préférerais ne pas avoir à faire cette pâte, mais si vous voulez qu'elle soit transparente, c'est le seul moyen que je peux trouver pour le faire.

47
MikeR

La solution de Mike R est bien, mais je préfère cette approche:

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 cette façon, vous redevenez PremierRépondeur uniquement lorsque cela est nécessaire.

23
Sandy

Je suis entré rdar contre ce problème, mais j'ai trouvé un moyen de contourner le problème. Vous devez essentiellement remplacer par programmation le contrôle "bloqué" par un nouveau. Le plus simple est d'archiver le contrôle existant dans viewDidLoad, puis de le désarchiver au besoin:

// 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://stackoverflow.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;
}
1
David H

Version rapide de la solution 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()
    }
}
0
David Rees

Avec iOS, vous ne devriez jamais essayer de "bidouiller" des choses, si le comportement que vous souhaitez n'est pas fourni par le framework, changez d'avis!

D'abord c'est plus facile ^^, ensuite l'utilisateur ne réagira pas à cela, alors vous ne saurez jamais si la prochaine mise à jour d'iOS va la casser ou non, cela peut donc être dangereux pour votre application.

"Vous voulez que l'utilisateur voie le mot de passe qu'il tape sur un champ de texte sécurisé", vous pouvez afficher un UILabel en bas? Ou une boîte d'alerte de confirmation avec le mot de passe vide?

0
Thomas Decaux