UITextField има крайно празно пространство след превключване на secureTextEntry

Имам бутон, който превключва между режим Show/Hide (т.е. превключва UITextField между secureTextEntry NO и YES). Целта на който е да позволи на потребителя да види паролата, която въвежда.

Следвах примера (с най-голям брой гласове) тук: UITextField secureTextEntry - работи при преминаване от ДА на НЕ, но промяната обратно на ДА няма ефект

Когато обаче задам secureTextEntry на NO, всеки текст, който е написан там, завършва с интервал в края. Това не изглежда да е проблем, когато зададете secureTextEntry на YES.

Например, ако въведа текста "моята парола", докато setSecureTextEntry е зададено на NO, и след това го превключа на YES, потребителят ще види ********** (10 точки), което е правилно. Ако задам SecureTextEntry на NO, потребителят ще види „моята парола“ (с интервал в края или поне курсорът се премества с един интервал надясно).

Важна забележка: В инструмента за отстраняване на грешки стойността на низа на текста се показва без интервал в края, както следва:

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

Опитах да изрежа празно пространство (съгласно избягвайте средното празно пространство в UITextField), но имаше без ефект.


person Brian Colavito    schedule 08.01.2013    source източник
comment
Мисля, че iOS продължава да рисува мигащия курсор в същата позиция. Точките са по-широки от текста, така че винаги има празнина между текста и курсора. „Празното поле“ всъщност не е в текстовото поле, просто изглежда така поради разположението на курсора.   -  person russau    schedule 23.01.2013


Отговори (18)


Току-що се сблъсках с този случай и най-накрая реших този проблем.

работи на най-новия iOS SDK, iOS 8.1

Първо, изобщо няма крайно пространство.

Символът точка (показан в SecureEntry) и нормалният знак имат различна ширина и след като превключите превключвателя isSecureEntry, курсорът не опреснява позицията си.

така че използвам това решение, за да разреша този проблем.

- (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

надявам се да помогне!

person sunus    schedule 15.12.2014
comment
Тези 3 реда за опресняване на курсора премахват празното пространство // Workaround to refresh cursor tmpString = self.passwordTextField.text; self.passwordTextField.text = @" "; self.passwordTextField.text = tmpString; - person simple_code; 07.01.2016

PRE-iOS-8.0 (решение с дата)... В метода на действие на вашия бутон (превключване между secureTextEntry ДА и НЕ), просто задайте свойството text на UITextField на текущата text стойност. Въпреки че това може да изглежда излишно и малко като хак, това ще преначертае курсора в правилната позиция. Ето пример за това как трябва да изглежда методът на действие на вашия бутон сега...

-(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... От iOS 8.0 изглежда, че настройката на text на UITextField вече не преначертава курсора, когато се извиква с низ, равен на текущата му стойност на низ. Сега трябва да направим тази крачка напред и действително да променим стойността text, преди да я нулираме отново. Заменете горния ред setText: с нещо подобно на тези редове.

// * 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
person Matthew    schedule 20.03.2014
comment
Прав си - изглежда, че настройката на iOS 8.0+ text на UITextField вече игнорира дублиращи се низове... Благодаря @sethfri и други коментатори. - person Matthew; 05.09.2015
comment
Това работи чудесно в 9.3 textField.text = textField.text (след превключване на защитено въвеждане на текст) - person 0x6A75616E; 28.03.2016

Имам чисто решение, което не се замърсява със свойството text на UITextField.

Увийте ги в този стил.

[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.
person tounaobun    schedule 30.11.2015
comment
Отлично. Работи и на iOS 11. Благодаря! - person David Weiss; 15.12.2017

За да заобиколите този бъг в iOS, можете просто да направите следното (работи за всяка версия на iOS):

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

Можете да го поправите по следния начин:

NSString *currentText = self.textfield.text;
self.textfield.text = @"";
self.textfield.text = currentText;
person Kingiol    schedule 29.09.2015

Това работи за мен на 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;
}
person Gonzo Oin    schedule 09.10.2014

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

Това е, което използвах за iOS 8

person David Carvalho    schedule 03.12.2014

Когато променим свойство textfield.secureTextEntry, позицията на каретката не се актуализира. За да коригирате това, кодът по-долу работеше преди IOS 8:

pwdTextField.text  = pwdTextField.text

Сега не става. Изглежда, че IOS 8 открива, че новата стойност е равна на старата стойност и не прави нищо. Така че, за да работи отново, трябва действително да променим стойността. Ето бързата версия, която работи за мен.

let str = pwdTextField.text
pwdTextField.text = str + " "
pwdTextField.text = str
person KeepWalking    schedule 03.12.2014

Това е друга възможност за решаване на този проблем, където self.passwordText е UITextField:

if (self.passwordText.isFirstResponder) {
    [self.passwordText resignFirstResponder];
    [self.passwordText becomeFirstResponder];
}
person mc_plectrum    schedule 20.02.2015

Изглежда, че второто решение в препратената връзка, когато е внедрено, има желаното поведение да не добавя допълнително пространство:

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

person Brian Colavito    schedule 08.01.2013

Това работи в моя случай

    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];
person Mihir Mehta    schedule 18.06.2015

Разширение Swift UITextField:

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

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

Задаването на решение textField.text също работи в някои ситуации, но не и за моите нужди (Персонализиран шрифт с две текстови полета. Причинява промени в шрифта и проблеми по време на изпълнение.) Добавяне и тук.

func toggleSecureEntry() {
    isSecureTextEntry.toggle()
    let originalText = text
    text = nil
    text = originalText
}
person anilgoktas    schedule 22.05.2016

За да накарам курсора да се позиционира правилно, настройката на атрибутите на шрифта изглежда свърши работа за мен.

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

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

Тестван на iOS8, iOS9. Дано помогне!

person Rahul    schedule 26.09.2015

Всеки път, когато текстът е зададен в UITextField, позицията на курсора се актуализира

Така че използвах този код

partial void btnShowPassword_ToutchUpInside (UIButton sender)
    {
        if (TxtPassword.SecureTextEntry == true) {
            TxtPassword.SecureTextEntry = false;
            TxtPassword.Text = TxtPassword.Text;
        } else {
            TxtPassword.SecureTextEntry = true;
        }
    }
person Hans-Peter    schedule 13.04.2016

Ето решението:

- (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];
}
person DHARMENDRA SINHA    schedule 25.06.2018
comment
Моля, опитайте се да форматирате кода на отговора си, за да изглежда по-четлив - person Failed Scientist; 25.06.2018
comment
@tuomastik, одобрих редакцията ти, но ти случайно разби кода и трябваше да го поправя. Моля, не премахвайте методите - например в goal-c - person Cœur; 25.06.2018

Използвам това, работи добре.

[self.yourTextField becomeFirstResponder];
person Ramdhas    schedule 31.08.2016

Суифт 4

Грешката е на радара, има и обяснение на заобиколното решение: http://www.openradar.me/38465011

Тук е изрязано временно решение за това как да актуализирате първоначално позицията на каретката (курсора).

// 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)
}
person dimpiax    schedule 17.08.2018

Имах подобен проблем и разбрах, че е защото актуализирах текста преди да настроя свойството secureTextEntry. Има смисъл, че textField ще изтегли каретката на мястото, на което ще бъде, ако използва secureTextEntry.

Не прочетох целия проблем, нито посетих решението, свързано от OP, но в случай, че някой друг има същия проблем като мен:

Опитайте да актуализирате текста си след като зададете свойството secureTextEntry.

person redmage1993    schedule 23.04.2019