Пули UITextField secureTextEntry с настраиваемым шрифтом?

Я использую собственный шрифт в UITextField, который secureTextEntry включен. Когда я печатаю в ячейке, я вижу маркеры выбранного мной шрифта, но когда поле теряет фокус, маркеры возвращаются к стандартному системному шрифту. Если я снова коснусь поля, они вернутся к моему шрифту и так далее.

Есть ли способ убедиться, что они продолжают отображать маркеры настраиваемого шрифта, даже если поле не в фокусе?

введите описание изображения здесь введите описание изображения здесь


person Luke    schedule 07.01.2014    source источник
comment
+1 Хороший вопрос. Интересно, сообщается ли об этой ошибке в Apple.   -  person Segev    schedule 07.01.2014
comment
Я подал сообщение о проблеме.   -  person Luke    schedule 07.01.2014
comment
Разве вам не следует принять stackoverflow.com/a/22596030/215282 ниже?   -  person Geri Borbás    schedule 02.05.2014
comment
Похоже, у нас уже есть аналогичный вопрос stackoverflow.com/questions/19475918/   -  person Abhijeet    schedule 27.10.2015
comment
связывание этого stackoverflow.com/a/33954746/1652402   -  person Daniel Galasko    schedule 27.11.2015
comment
Работает на iOS 8 и 9 и, возможно, 7 не тестировалось: stackoverflow.com/a/34777286/1151916   -  person Ramis    schedule 22.01.2016


Ответы (10)


Подкласс, который решает эту проблему. Создайте произвольный UITextField, затем установите для свойства secure значение YES (через KVC в IB).

Фактически он реализует комментарий, предложенный lukech. Когда текстовое поле завершает редактирование, оно переключается на произвольное текстовое поле, затем устанавливает в него множество точек и взламывает text аксессор, чтобы всегда получать фактический текст, содержащийся в поле.

@interface SecureTextFieldWithCustomFont : UITextField
@property (nonatomic) BOOL secure;
@property (nonatomic, strong) NSString *actualText;
@end


@implementation SecureTextFieldWithCustomFont


-(void)awakeFromNib
{
    [super awakeFromNib];

    if (self.secureTextEntry)
    {
        // Listen for changes.
        [self addTarget:self action:@selector(editingDidBegin) forControlEvents:UIControlEventEditingDidBegin];
        [self addTarget:self action:@selector(editingDidChange) forControlEvents:UIControlEventEditingChanged];
        [self addTarget:self action:@selector(editingDidFinish) forControlEvents:UIControlEventEditingDidEnd];
    }
}

-(NSString*)text
{
    if (self.editing || self.secure == NO)
    { return [super text]; }

    else
    { return self.actualText; }
}

-(void)editingDidBegin
{
    self.secureTextEntry = YES;
    self.text = self.actualText;
}

-(void)editingDidChange
{ self.actualText = self.text; }

-(void)editingDidFinish
{
    self.secureTextEntry = NO;
    self.actualText = self.text;
    self.text = [self dotPlaceholder];
}

-(NSString*)dotPlaceholder
{
    int index = 0;
    NSMutableString *dots = @"".mutableCopy;
    while (index < self.text.length)
    { [dots appendString:@"•"]; index++; }
    return dots;
}


@end

Может быть расширен для работы с экземплярами, отличными от NIB, обработки значений по умолчанию и т. Д., Но вы, вероятно, поняли идею.

person Geri Borbás    schedule 23.03.2014
comment
Спасибо за это, отлично работает. Я немного улучшил ваш код: 1) избавился от свойства secure (ненужное IMO, я предполагаю, что все текстовые поля этого подкласса безопасны); 2) избегать редактирования обновлений DidChange; 3) реализовать соответствующий метод setText :. Вы можете найти его здесь: gist.github.com/rsanchezsaez/9836102. - person Ricardo Sanchez-Saez; 28.03.2014
comment
Я не могу точно вспомнить, но у меня были еще проблемы с защищенными текстовыми полями (при запуске), поэтому я решил вместо этого переключиться на произвольный UITextFields в качестве отправной точки. - person Geri Borbás; 02.04.2014
comment
Я создал категорию на UITextField, чтобы исправить эту проблему: github.com/elegion/ELFixSecureTextFieldFont (на основе вашего ответа ) - person glyuck; 02.04.2014
comment
@glyuck, ваше решение кажется намного более сложным. Почему ты сказал, что так лучше? - person André Fratelli; 16.12.2014
comment
это решение не работает в 100% случаев. Я заметил, что пароль, отправленный на сервер, имеет следующие ведущие символы: • (они могут быть точками). Я думаю, что-то где-то напортачили. - person Alberto M; 03.11.2017
comment
Вау, как-то странно, что это все еще проблема 4 года спустя. ???? - person Geri Borbás; 12.04.2018

Для тех, у кого возникли проблемы с потерей пользовательских шрифтов при переключении secureTextEntry, я нашел обходной путь (я использую iOS 8.4 SDK). Я пытался сделать переключатель для отображения / скрытия пароля в UITextField. Каждый раз, когда я переключал secureTextEntry = NO, мой пользовательский шрифт сбивался, и только последний символ отображал правильный шрифт. С этим определенно творится что-то напуганное, но вот мое решение:

-(void)showPassword {
    [self.textField resignFirstResponder];
    self.textField.secureTextEntry = NO;
}

Первому респонденту по какой-то причине необходимо уволиться. Кажется, вам не нужно отказываться от первого респондента, если для параметра secureTextEntry установлено значение YES, только если установлено значение NO.

person Joshua Haines    schedule 04.08.2015

Фактическая проблема заключается в том, что в режиме редактирования (UITextField не отрисовывается собственный текст во время редактирования) для рисования отредактированных символов используются маркеры (U + 2022), а в UITextField черные кружки (U + 25CF) . Я предполагаю, что в шрифтах по умолчанию эти символы выглядят одинаково.

Вот альтернативный обходной путь для всех, кто интересуется, который использует подкласс настраиваемого текстового поля, но не требует манипулирования свойством текста или другой специальной конфигурации. ИМО, это сохраняет относительно чистоту.

@interface MyTextField : UITextField
@end

@implementation MyTextField

- (void)drawTextInRect:(CGRect)rect
{
    if (self.isSecureTextEntry)
    {
        NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
        paragraphStyle.alignment = self.textAlignment;

        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        [attributes setValue:self.font forKey:NSFontAttributeName];
        [attributes setValue:self.textColor forKey:NSForegroundColorAttributeName];
        [attributes setValue:paragraphStyle forKey:NSParagraphStyleAttributeName];

        CGSize textSize = [self.text sizeWithAttributes:attributes];

        rect = CGRectInset(rect, 0, (CGRectGetHeight(rect) - textSize.height) * 0.5);
        rect.origin.y = floorf(rect.origin.y);

        NSMutableString *redactedText = [NSMutableString new];
        while (redactedText.length < self.text.length)
        {
            [redactedText appendString:@"\u2022"];
        }

        [redactedText drawInRect:rect withAttributes:attributes];
    }
    else
    {
        [super drawTextInRect:rect];
    }
}

@end
person Austin    schedule 11.06.2014
comment
Это сработало как шарм, спасибо! Единственным недостатком этого метода является то, что пули немного прыгают при входе в режим редактирования и выходе из него. Это можно исправить жестким кодированием rect.origin.y, но, может быть, есть более чистое решение? - person maxkonovalov; 13.06.2014
comment
Ха, в моей ситуации произошел скачок, если я пропустил оператор rect.origin.y = floorf(rect.origin.y). Возможно, лучше использовать roundf() вместо floorf(). - person Austin; 13.06.2014
comment
Понятно, но в моем случае мне пришлось установить origin.y равным 1.5, поэтому он может отличаться в зависимости от шрифта и размера текста ... - person maxkonovalov; 13.06.2014
comment
метод drawTextInRect никогда не вызывается. - person Tapan Thaker; 14.07.2014
comment
@ Остин отлично работает! Мне ваше решение нравится больше, чем решение Джери. Отличная работа! - person mokagio; 13.01.2015

Хотя это ошибка iOS (и я должен добавить, что она новая в iOS 7), у меня есть другой способ обойти ее, который может оказаться приемлемым. Функциональность все еще немного ухудшилась, но не намного.

По сути, идея состоит в том, чтобы установить для шрифта семейство / стиль шрифтов по умолчанию всякий раз, когда в поле что-то введено; но если ничего не введено, установите свой собственный шрифт. (Размер шрифта можно оставить в покое, поскольку это семейство / стиль, а не размер, который является ошибочным.) Улавливайте каждое изменение значения поля и устанавливайте шрифт соответствующим образом в это время. Тогда слабый текст «подсказки», когда ничего не введено, будет иметь нужный вам шрифт (пользовательский); но при вводе чего-либо (редактируете вы или нет) будет использоваться значение по умолчанию (Helvetica). Поскольку пули являются пулями, это должно выглядеть нормально.

Единственным недостатком является то, что при вводе символов перед заменой маркеров будет использоваться шрифт по умолчанию (Helvetica). Но это только доли секунды на символ. Если это приемлемо, то это решение работает.

person RedRedSuit    schedule 24.01.2014

Я нашел уловку для этой проблемы.

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
   if ([textField tag]== TAG_PASS || [textField tag]== TAG_CPASS)
    {
       // To fix password dot size
        if ([[textField text] isEqualToString:@"" ])
        {
          [textField setText:@" "];
          [textField resignFirstResponder];
          [textField becomeFirstResponder];
          [textField setText:@""];
        }  
    }
}
person Parul    schedule 03.07.2015
comment
Это можно легко сделать и вне этого метода. Хорошая находка Парул. - person Damien Justin Šutevski; 15.01.2016

[passWordTextField resignFirstResponder];
passWordTextField.secureTextEntry = !passWordTextField.secureTextEntry;
[passWordTextField becomeFirstResponder];

Это самый быстрый способ решить эту ошибку!

person AaronTKD    schedule 21.03.2016
comment
Когда он снова станет первым респондентом, а пользователь продолжит вводить текст, все, что было набрано ранее, будет удалено. - person Patrick Lynch; 16.06.2016
comment
Код просто запускается, когда пользователь начинает печатать, но не печатает. Так что очищать нечего. - person AaronTKD; 20.06.2016

iOS ведет себя немного странно, когда дело доходит до пользовательских шрифтов. Попробуйте удалить "Adjust to Fit" для этого текстового поля. Если это не сработает, я предполагаю, что вас беспокоит увеличение размера шрифта.

Простое решение для этого:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    if(textField.secureTextEntry)
    {
        [textField setFont:[UIFont fontWithName:@"Helvetica-Bold" size:10.0]];
    }
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
    if(textField.secureTextEntry)
    {
        [textField setFont:[UIFont fontWithName:@"Helvetica-Bold" size:10.0]];
    }
}

Вам нужно немного поиграть с размером, чтобы он выглядел так, будто при потере фокуса на UITextField размер не изменился.

Если у вас есть серьезная проблема с интервалом между символами, как в отредактированном вопросе, самым простым (и немного уродливым) решением было бы создать изображение пули, которое соответствует указанным выше размеру и интервалу и соответствует количеству символов, введенных пользователем, которое будет появляются, когда пользователь покидает UITextField.

person Segev    schedule 07.01.2014
comment
Это происходит с любым пользовательским шрифтом, который я использую, будь то TTF, OTF и т. Д. Я пробовал несколько. И Adjust To Fit тоже, к сожалению, не имеет значения :( - person Luke; 07.01.2014
comment
Боюсь, это не имеет значения. Шрифт по-прежнему возвращается к системному стандарту всякий раз, когда я выхожу из текстового поля. - person Luke; 07.01.2014
comment
@lukech Приведенный выше код отлично работает для всех пользовательских шрифтов, которые я пробовал. Убедитесь, что UITextField имеет делегата и что методы, указанные выше, вызываются. - person Segev; 07.01.2014
comment
Да, они определенно есть. Если я устанавливаю размер шрифта, он его уважает, поэтому маркеры становятся больше, но установка самого шрифта игнорируется. - person Luke; 07.01.2014
comment
@lukech Почему вас волнует начертание шрифта, если все, что видит пользователь, - это черные точки? Я могу думать об одном сценарии, например, об интервале между буквами, так ли это? - person Segev; 07.01.2014
comment
Я хочу использовать маркер из пользовательского шрифта, а не маркер Helvetica. Кроме того, они видят каждый символ по мере его ввода, как это обычно бывает. Этот символ должен быть в специальном шрифте. Это поле пароля, поэтому оно должно совпадать с именем пользователя и т. Д. Мне это определенно кажется ошибкой iOS, нет причин, по которым он не должен подчиняться шрифту, когда он не в фокусе. - person Luke; 07.01.2014
comment
@lukech iOS всегда будет использовать маркеры по умолчанию, что касается вашего второго аргумента, я вижу настраиваемый шрифт по мере ввода, даже после того, как я перефокусируюсь на UITextField. - person Segev; 07.01.2014
comment
Правильно. По мере ввода вы будете видеть текст с произвольным шрифтом и маркеры, а затем, как только вы измените поля, маркеры поменяются. Затем, если вы снова войдете в ячейку, пули вернутся обратно. Это уродливый, нежелательный и непоследовательный интерфейс, и это проблема, которую я пытаюсь исправить здесь :) - person Luke; 07.01.2014
comment
@lukech И это вполне понятно, но, насколько я могу судить, если вы, например, не используете сумасшедший шрифт, такой как Zapfino, единственное, о чем вам нужно заботиться, это его размер. Между отклеиванием ленты и перефокусировкой на UITextField размер шрифта является главным заметным. - person Segev; 07.01.2014
comment
Я добавил изображение, показывающее два маркера - как вы можете видеть, они очень разные, и пользователю довольно неприятно видеть, как они меняются взад и вперед. - person Luke; 07.01.2014
comment
@lukech Это немного некрасиво в сделанном. Я обновил свой ответ. - person Segev; 07.01.2014
comment
Я думаю, что самый простой способ - просто отключить secureTextEntry в точке didEndEditing и создать строку, содержащую нужное количество маркеров, затем установить ее на это и отслеживать фактический пароль отдельно, а затем менять его по мере необходимости . - person Luke; 07.01.2014
comment
Ого, я попробую это выше. - person Geri Borbás; 23.03.2014

secureTextEntry текстового поля можно вообще избежать:

NSString *pin = @"";
BOOL pasting = FALSE;
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if(!pasting) {
        pin = [pin stringByReplacingCharactersInRange:range withString:string];

        // Bail out when deleting a character
        if([string length] == 0) {
            return YES;
        }

        pasting = TRUE;
        [textField paste:@"●"];

        return NO;
    } else {
        pasting = FALSE;
        return YES;
    }
}
person Randomblue    schedule 23.10.2015

Я рекомендую resignFirstResponder перед изменением scureTextEntry, а затем снова статьFirstResponder, как он размещен здесь: https://stackoverflow.com/a/34777286/1151916

person Ramis    schedule 22.01.2016

Swift 5 и iOS 14 уже есть, но isSecureTextEntry, установленный в true для пользовательского шрифта, по-прежнему отображает маркеры неправильного размера, хотя фактическая начальная буква имеет правильный размер.

Ни одно из решений от переполнения стека у меня не сработало, кроме хакерского обходного пути для установки шрифта на системный шрифт, когда пароль находится в безопасном режиме.

  if textField.isSecureTextEntry {
            self.textField.font = UIFont.systemFont(ofSize: 17)
    } else {
        self.textField.font = UIFont(name: "Roboto-Regular", size: 17)
    }
person Mishka    schedule 11.05.2021