UITextField has trailing whitespace after secureTextEntry toggle

[亡魂溺海] 提交于 2020-01-21 00:45:08

问题


I have a button that toggles between Show/Hide mode (i.e. toggles a UITextField between secureTextEntry NO and YES). The purpose of which is to allow the user to see the password they are entering.

I followed the example (with the highest number of votes) here: UITextField secureTextEntry - works going from YES to NO, but changing back to YES has no effect

However, when I set secureTextEntry to NO, any text that was written there ends up with a space at the end. This does not seem to be a problem when setting secureTextEntry to YES.

For example, if I enter the text "mypassword" while setSecureTextEntry is set to NO, and then switch it to YES, the user will see ********** (10 dots), which is correct. If I setSecureTextEntry to NO, the user will see "mypassword " (with a space at the end, or at least, the cursor moved one space to the right).

Important note: In the debugger, the string value of text appears without the trailing space, like this:

(lldb) expr self.passwordText.text
(NSString *) $0 = 0x1d8450e0 @"mypassword"

I have tried trimming whitespace (per avoid middle whitespace in UITextField), but it has had no effect.


回答1:


i've just encounter this case and finally solved this problem.

works on Latest iOS SDK, iOS 8.1

First of all, there is no trailing space at all.

The dot(shown in SecureEntry) character and normal character have different width and after you toggle isSecureEntry switch, the cursor didn't refresh it's position.

so i use this workaround to solved this problem.

- (void)toggle
{
    NSString *tmpString;
    [self.passwordTextField setSecureTextEntry:!self.passwordTextField.isSecureTextEntry];
    if (self.passwordTextField.isSecureTextEntry) {
       // do stuffs
    } else {
       // do other stuffs
    }
    // Workaround to refresh cursor
    tmpString = self.passwordTextField.text;
    self.passwordTextField.text = @" ";
    self.passwordTextField.text = tmpString;
}

Swift 3+

   // Workaround to refresh cursor

    let currentText: String = self.userPassword.text!
    self.userPassword.text = "";
    self.userPassword.text = currentText

hope it helps!




回答2:


PRE-iOS-8.0 (dated solution)... In your button's action method (toggling between secureTextEntry YES and NO), simply set UITextField's text property to its current text value. Although this may seem redundant and a bit like a hack, this will redraw the cursor in the right position. Here's an example of what your button's action method should look like now...

-(void)toggleButtonPressed:(UIButton*)sender
{
    // Toggle between secure and not-so-secure entry
    self.toggleButton.selected = !self.toggleButton.selected;
    self.textfield.secureTextEntry = !self.toggleButton.selected;

    // * Redundant (but necessary) line *
    [self.textfield setText:self.textfield.text];
}

POST-iOS-8.0... As of iOS 8.0, it appears that UITextField's text setter no longer redraws the cursor when called with a string equal to its current string value. Now, we need to take this a step further and actually change the text value before resetting it again. Replace the above setText: line with something like these lines.

// * Extra redundant (but necessary) lines *
NSString *currentText = self.textfield.text;
[self.textfield setText:@"Arbitrary string..."]; // Change the value
[self.textfield setText:currentText]; // Reset the value



回答3:


I have a clean solution not going dirty with text property of UITextField.

Wrap them in this style.

[self.passwordTextField resignFirstResponder]; // first resign its first responder.

// change `secureTextEntry` property's value if necessary.

if (self.passwordTextField.secureTextEntry) {
    self.passwordTextField.secureTextEntry = NO;
    self.passwordEcryptButton.selected = YES;
}else{
    self.passwordTextField.secureTextEntry = YES;
    self.passwordEcryptButton.selected = NO;
}

[self.passwordTextField becomeFirstResponder];  // finally gain its first responder again.



回答4:


In order to work around this bug in iOS you can simply do the following (works for any iOS version):

- (IBAction)toggleSecureTextEntry:(UIButton *)button
{
    self.textField.secureTextEntry = !self.textField.secureTextEntry;
    NSString *originalText = self.textField.text;
    self.textField.text = nil;
    self.textField.text = originalText;
}



回答5:


You can fix it like this:

NSString *currentText = self.textfield.text;
self.textfield.text = @"";
self.textfield.text = currentText;



回答6:


This work for me on iOS 8

if (self.passwordTextField.secureTextEntry) {
    // Display password and keep selected text range
    UITextRange *selectedTextRange = self.passwordTextField.selectedTextRange;
    NSString *password = self.passwordTextField.text;
    self.passwordTextField.secureTextEntry = NO;
    self.passwordTextField.text = [@"" stringByPaddingToLength:password.length withString:@" " startingAtIndex:0]; // Done for carret redrawing
    self.passwordTextField.text = password;
    self.passwordTextField.selectedTextRange = selectedTextRange;
}
else {
    // Hide password and keep selected text range
    UITextRange *selectedTextRange = self.passwordTextField.selectedTextRange;
    NSString *password = self.passwordTextField.text;
    self.passwordTextField.secureTextEntry = YES;
    self.passwordTextField.text = [@"" stringByPaddingToLength:password.length withString:@" " startingAtIndex:0]; // Done for carret redrawing
    self.passwordTextField.text = password;
    self.passwordTextField.selectedTextRange = selectedTextRange;
}



回答7:


UITextPosition *beginning = [self.passwordField beginningOfDocument];
[self.passwordField setSelectedTextRange:[self.passwordField textRangeFromPosition:beginning
                                                                        toPosition:beginning]];

UITextPosition *end = [self.passwordField endOfDocument];
[self.passwordField setSelectedTextRange:[self.passwordField textRangeFromPosition:end
                                                                        toPosition:end]];

This is what I used for iOS 8




回答8:


When we change a textfield.secureTextEntry property, the caret position is not updated. To fix this, the code below used to work before IOS 8:

pwdTextField.text  = pwdTextField.text

Now it doesn't. It seems IOS 8 detects the new value equals old value and does nothing. So to make it work again we have to actually change the value. Here is the swift version that works for me.

let str = pwdTextField.text
pwdTextField.text = str + " "
pwdTextField.text = str



回答9:


This is another possibility to solve this issue, where self.passwordText is the UITextField:

if (self.passwordText.isFirstResponder) {
    [self.passwordText resignFirstResponder];
    [self.passwordText becomeFirstResponder];
}



回答10:


It appears that the second solution in the referenced link, when implemented, has the desired behavior of not adding an extra space:

https://stackoverflow.com/a/8495888/738190




回答11:


This Works in my case

    BOOL wasFirstResponder = [self.passwordTextField isFirstResponder];
    if([self.passwordTextField isSecureTextEntry])
    {
        //This three lines are key
        self.passwordTextField.delegate = nil;
        [self.passwordTextField resignFirstResponder];
        self.passwordTextField.delegate = self;
    }

    [self.passwordTextField setSecureTextEntry: !self.passwordTextField.isSecureTextEntry];
    if(wasFirstResponder)
        [self.passwordTextField becomeFirstResponder];



回答12:


Swift UITextField extension:

extension UITextField {
    func toggleSecureEntry() {
        let wasFirstResponder = isFirstResponder

        if wasFirstResponder { resignFirstResponder() }
        isSecureTextEntry.toggle()
        if wasFirstResponder { becomeFirstResponder() }
    }
}

Setting textField.text solution also works in some situations but not for my need (Custom font with two text fields. Caused font changes and glitches on runtime.) Adding here too.

func toggleSecureEntry() {
    isSecureTextEntry.toggle()
    let originalText = text
    text = nil
    text = originalText
}



回答13:


To get the cursor to reposition correctly, setting the font attributes seemed to do the trick for me.

// Hack to update cursor position
self.passwordTf.defaultTextAttributes = @{NSFontAttributeName: textFieldFont, NSForegroundColorAttributeName: textFieldColor};

// Change secure entry
self.passwordTf.secureTextEntry = !self.passwordTf.secureTextEntry;

Tested on iOS8, iOS9. Hope it helps!




回答14:


Everytime the text is set in the UITextField, the cursor postition is updated

So I used this code

partial void btnShowPassword_ToutchUpInside (UIButton sender)
    {
        if (TxtPassword.SecureTextEntry == true) {
            TxtPassword.SecureTextEntry = false;
            TxtPassword.Text = TxtPassword.Text;
        } else {
            TxtPassword.SecureTextEntry = true;
        }
    }



回答15:


Here is the solution:

- (void)showHidePassword:(UIButton *)sender {
    EDSignUpCell *cell = [self.signUpTblView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:0]];
    if(!TRIM_SPACE(cell.cellTextField.text).length) {return;}
    [cell.showHidePasswordBtn setSelected:!cell.showHidePasswordBtn.isSelected];
    cell.cellTextField.secureTextEntry = cell.showHidePasswordBtn.isSelected;
    [cell.cellTextField setText:cell.cellTextField.text];
    [cell.cellTextField becomeFirstResponder];
}



回答16:


I'm using this, Works fine.

[self.yourTextField becomeFirstResponder];



回答17:


Swift 4

Bug is on radar, there is explanation of workaround also: http://www.openradar.me/38465011

Here is cut of temporary workaround how to natively update caret (cursor) position.

// update caret position
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
    let (beginning, end) = (self.beginningOfDocument, self.endOfDocument)

    self.selectedTextRange = self.textRange(from: beginning, to: end)
    self.selectedTextRange = self.textRange(from: end, to: end)
}



回答18:


I had a similar issue and realized it was because I was updating the text before setting the secureTextEntry property. It makes sense that the textField would draw out the caret at the location it'd be at if it were using secureTextEntry.

I did not read the entire problem nor did I visit the solution linked by OP, but in case someone else has the same issue as me:

Try updating your text after setting the secureTextEntry property.



来源:https://stackoverflow.com/questions/14220187/uitextfield-has-trailing-whitespace-after-securetextentry-toggle

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!