Управление текстовыми полями и текстовыми представлениями

Текстовые поля и текстовые представления имеют две основных функции: вывести на экран текст и включить запись и редактирование текста. Несколько задач программирования связаны с этими простыми целями, включая конфигурирование текстового объекта, доступ к текущему тексту, проверку, что пользователь вводит, и выводящий на экран представления наложения, такие как кнопки закладки в текстовых полях.

Делегат a UITextField или UITextView объект ответственен за большинство этих задач. Делегат должен принять UITextFieldDelegate или UITextViewDelegate протоколы и реализуйте один или больше методов протокола. Реализация всех методов протокола является дополнительной. Для вызывания этих методов необходимо установить delegate свойства текстовых полей и текста просматривают или программно или в Интерфейсном Разработчике.

Последовательность сообщений делегату

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

Существует несколько исключений к этому общему поведению. На iPad, если контроллер представления модально представляет свое представление с помощью «стиля» листа формы, не скрыта клавиатура, когда-то показанная, пока пользователь не касается отклонить ключа, или модальный контроллер представления программно отклонен. Цель этого поведения состоит в том, чтобы избежать чрезмерных анимаций, когда пользователь перемещается между представлениями, которые являются в основном, но не полностью, текстовые поля. Другое исключение включает пользовательские входные представления. Входное представление является заменой для системных клавиатур, присваивающейся inputView свойство текстового представления или пользовательского представления. Когда там вводятся представления, UIKit мог бы выгрузить клавиатуру, даже когда текстовый объект является первым респондентом, и это могло бы показать подобное клавиатуре входное представление от имени разработчика для нетекстовых объектов.

Последовательность сообщений, что и текстовые представления и текстовые поля отправляют их делегатам, следующие:

  1. Непосредственно перед тем, как текстовый объект становится первым респондентомtextFieldShouldBeginEditing: (текстовое поле) и textViewShouldBeginEditing: (текстовое представление).

    Делегат может проверить, должен ли текстовый объект стать первым респондентом путем возврата YES (значение по умолчанию) или NO.

  2. Сразу после того, как текстовый объект становится первым респондентомtextFieldDidBeginEditing: (текстовое поле) и textViewDidBeginEditing: (текстовое представление).

    Делегат может реагировать на это сообщение путем обновления информации состояния или, например, путем показа представления наложения во время сеанса редактирования.

  3. Во время сеанса редактирования — различный.

    В то время как пользователь вводит и редактирует текст, текстовый объект вызывает определенные методы делегации (если реализовано). Например, делегат текстового представления может получить a textViewDidChange: обменивайтесь сообщениями, когда изменится любой текст. Делегат текстового поля может получить a textFieldShouldClear: обменивайтесь сообщениями, когда пользователь коснется ясной кнопки текстового поля; делегат возвращает булево значение, указывающее, должен ли быть очищен текст.

  4. Непосредственно перед тем, как текстовый объект оставляет первого респондентаtextFieldShouldEndEditing: (текстовое поле) и textViewShouldEndEditing: (текстовое представление).

    Основная причина для делегата реализовать эти методы состоит в том, чтобы проверить введенный текст. Например, если текст должен соответствовать данному формату, делегат проверяет вводимую строку здесь и возвраты NO если не соответствует строка. Возвращаемое значение по умолчанию YES.

    Связанный метод для текстовых полей textFieldShouldReturn:. Когда пользователь касается клавиши Return, класс текстового поля отправляет a textFieldShouldReturn: обменивайтесь сообщениями делегату, чтобы спросить, должно ли это оставить первого респондента.

  5. Сразу после текста объект оставляет первого респондентаtextFieldDidEndEditing: (текстовое поле) и textViewDidEndEditing: (текстовое представление).

    Делегат может реализовать эти методы для получения текста, который пользователь только что ввел или отредактировал.

Объектам кроме делегата можно сообщить об изменениях в состоянии первого респондента текстовых представлений и текстовых полей путем наблюдения уведомлений. (Они не могут, однако, утвердить или отклонить переход к новому состоянию.) Уведомления имеют имена такой как UITextFieldTextDidBeginEditingNotification, UITextViewTextDidEndEditingNotification, и UITextViewTextDidChangeNotification. Как с textFieldDidEndEditing: и textViewDidEndEditing:, основная причина наблюдения и обработки UITextFieldTextDidEndEditingNotification и UITextViewTextDidEndEditingNotification уведомления должны получить доступ к тексту в связанном текстовом поле или текстовом представлении. Посмотрите Ссылку класса Ссылки класса и UITextView UITextField для узнавания больше об уведомлениях, отправленных этими классами.

Конфигурирование текстовых полей и текстовых представлений

Как с любым объектом представления, предоставленным платформой UIKit, обычно необходимо конфигурировать текстовые поля и текстовые представления, прежде чем они будут выведены на экран. Можно сконфигурировать их или программно или использование инспектора атрибута Интерфейсного Разработчика. В любом случае Вы устанавливаете свойство текстового объекта.

Некоторые свойства характерны для текстовых представлений и текстовых полей, и другие являются определенными для каждого типа объекта, включая следующее:

Отслеживание многократных текстовых полей или текстовых представлений

Все методы UITextFieldDelegate или UITextViewDelegate протоколы имейте параметр, идентифицирующий текстовое поле или текстовое представление с изменением в состоянии первого респондента, изменением в значении или любым другим изменением, которое является причиной сообщения делегации. Если существует только один текстовый объект в в настоящее время выводимом на экран представлении, идентификационные данные текстового объекта, на который ссылается параметр, очевидны. Однако, если в настоящее время выводимое на экран представление имеет многократные текстовые поля или текстовые представления, делегат должен найти способ идентифицировать текстовый объект, который является предметом сообщения делегации.

Можно сделать это определение с помощью одного из двух подходов: выходы или теги. Для подхода выхода объявите переменную экземпляра выхода (использующий IBOutlet ключевое слово), и затем делают соединение розетки. В Вашем методе делегации протестируйте, является ли переданным - в текстовом объекте тот же объект, на который ссылается выход, с помощью сравнения указателя. Например, скажите, что Вы объявляете и соединяете названный выход SSN. Ваш код мог бы посмотреть что-то как Перечисление 3-1.

Перечисление 3-1  , Идентифицирующее переданный - в текстовом объекте с помощью выхода

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    if (textField == SSN) {
            // .....
            return NO;
        }
    return YES;
}

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

Для подхода тега объявите ряд enum константы, одна константа для каждого тега.

enum {
    NameFieldTag = 0,
    EmailFieldTag,
    DOBFieldTag,
    SSNFieldTag
};

Тогда присвойте целочисленное значение tag свойство текстового объекта, или программно или в инспекторе атрибута Интерфейсного Разработчика. ( tag свойство объявляется UIView.) В методе делегации можно использовать оператор переключения, чтобы оценить значение тега переданного - в текстовом объекте и продолжиться соответственно (как показано в Перечислении 3-2).

Перечисление 3-2  , Идентифицирующее переданный - в текстовом объекте с помощью тегов

- (void)textFieldDidEndEditing:(UITextField *)textField {
 
    switch (textField.tag) {
        case NameFieldTag:
            // do something with this text field
            break;
        case EmailFieldTag:
             // do something with this text field
            break;
        // remainder of switch statement....
    }
}

Получение введенного текста и установка текста

После того, как пользователь вводит или редактирует текст в текстовом поле или текстовом представлении и концах сеанса редактирования, делегат должен получить текст и сохранить его в модели данных приложения. Лучшие методы делегации для доступа к введенному тексту textFieldDidEndEditing: (текстовые поля) и textViewDidEndEditing: (текстовые представления).

Перечисление 3-3 иллюстрирует, как Вы могли бы получить текст, который пользователь ввел в текстовом поле (дифференцирующийся среди многократных текстовых полей в представлении с помощью тегов). текст свойство из UITextField или UITextView содержит строку, в настоящее время выводимую на экран текстовым объектом. Делегат получает строку от этого свойства и хранит его в объекте словаря использование ключа, определенного для каждого поля. Если текстовое поле не имеет никакого строкового значения — т.е. поле содержит пустую строку — делегат просто возвращается.

Перечисление 3-3  , Получающее текст, ввело в текстовое поле

- (void)textFieldDidEndEditing:(UITextField *)textField {
    if ([textField.text isEqualToString:@""])
        return;
 
    switch (textField.tag) {
        case NameFieldTag:
            [thePerson setObject:textField.text forKey:MyAppPersonNameKey];
            break;
        case EmailFieldTag:
            [thePerson setObject:textField.text forKey:MyAppPersonEmailKey];
            break;
        case SSNFieldTag:
            [thePerson setObject:textField.text forKey:MyAppPersonSSNKey];
            break;
        default:
            break;
    }
}

Перечисление 3-4 показывает реализацию textViewDidEndEditing: метод, получающий выведенную на экран строку от текстового представления и хранящий его в словаре. Здесь метод не просит, чтобы текстовое представление оставило первого респондента. ( resignFirstResponder когда пользователь коснулся кнопки Done в пользовательском интерфейсе представления, метод вызвали ранее в методе действия, вызванном.)

Перечисление 3-4  , Получающее текст, ввело в текстовое представление

- (void)textViewDidEndEditing:(UITextView *)textView {
    NSString *theText = textView.text;
    if (![theText isEqualToString:@""]) {
        [thePerson setObject:theText forKey:MyAppPersonNotesKey];
    }
    doneButton.enabled = NO;
}

Если необходимо записать, что строка оценивает текстовым объектам — обычно после получения их от модели данных приложения — просто присваивают строки text свойство текстового объекта. Например:

NSString *storedValue = [thePerson objectForKey:MyAppPersonEmailKey];
emailField.text = storedValue;

Чтобы сделать это, полезно определить выходы для каждого текстового поля или текстового представления, что Вы хотите записать, что строка оценивает (emailField, в этом примере).

Используя средства форматирования с текстовыми полями

Объекты средства форматирования автоматически анализируют строки в определенном формате и преобразовывают строку в объект, представляющий число, дату или другое значение; они также работают наоборот, преобразовывая NSDate, NSNumber, и подобные объекты к отформатированной строке, представляющей те объектные значения. Платформа Основы обеспечивает абстрактный базовый класс NSFormatter и два конкретных подкласса того класса, NSDateFormatter и NSNumberFormatter. Используя эти классы, пользователи могут ввести значения, такие как следующее в текстовое поле:

11/15/2010
-1,348.09

И Ваше приложение может использовать объекты средства форматирования преобразовать строки в NSDate возразите и NSNumber объект, соответственно.

Следующие листинги кода используют объект средства форматирования даты проиллюстрировать использование средств форматирования. (Конечно, Вы могли использовать a UIDatePicker объект для ввода даты, а не текстового поля, но текстового поля с присоединенным средством форматирования даты является другой опцией.) Код в Перечислении 3-5 создает NSDateFormatter возразите и присваивает его переменной экземпляра. Это конфигурирует средство форматирования даты для использования “короткого стиля” для дат, но в пути, который является быстро реагирующим к изменениям в календаре, локали и часовом поясе. Это также присваивает сегодняшнюю дату в данном формате как строка заполнителя так, чтобы у пользователей была модель для следования, когда они вводят даты.

Перечисление 3-5  , Конфигурирующее средство форматирования даты

- (void)viewDidLoad {
    [super viewDidLoad];
    dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setGeneratesCalendarDates:YES];
    [dateFormatter setLocale:[NSLocale currentLocale]];
    [dateFormatter setCalendar:[NSCalendar autoupdatingCurrentCalendar]];
    [dateFormatter setTimeZone:[NSTimeZone defaultTimeZone]];
    [dateFormatter setDateStyle:NSDateFormatterShortStyle]; // example: 4/13/10
    DOB.placeholder = [NSString stringWithFormat:@"Example: %@", [dateFormatter stringFromDate:[NSDate date]]];
 
    // code continues....
}

После конфигурирования средства форматирования даты делегат может вызвать dateFromString: метод на средстве форматирования для преобразования вводимой строки даты в NSDate объект, как показано в Перечислении 3-6.

Перечисление 3-6  Используя NSDateFormatter возразите для преобразования строки даты в объект даты

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [textField resignFirstResponder];
    if ([textField.text isEqualToString:@""])
        return;
    switch (textField.tag) {
        case DOBField:
            NSDate *theDate = [dateFormatter dateFromString:textField.text];;
            if (theDate)
                [inputData setObject:theDate forKey:MyAppPersonDOBKey];
            break;
        // more switch case code here...
        default:
            break;
    }
}

Использование средств форматирования не гарантирует, что вводимая строка содержит допустимые значения — например, пользователь мог войти 13 для числа месяца в Григорианском календаре. Чтобы гарантировать, что пользователь ввел правильное значение, делегат должен проверить строку, как объяснено в Проверке Введенного текста. И потому что проверка часто требует известного формата и диапазона допустимых значений при конфигурировании средства форматирования даты как в Перечислении 3-5 так, чтобы это было чувствительно к различным календарям и локалям, формат не может быть известен с уверенностью. Для указания известного формата даты сконфигурируйте средство форматирования даты путем вызова setDateFormat:, передача в образце формата определяется стандартом Unicode.

Можно также инвертировать процедуру, показанную выше: Преобразуйте объект даты в строку в данном формате путем вызова NSDateFormatter метод stringFromDate: и затем присвойте ту строку text свойство текстового поля, текстового представления или метки.

Для получения дополнительной информации о NSDateFormatter и NSNumberFormatter, посмотрите Руководство по Форматированию данных.

Проверка введенного текста

Приложение иногда не может принимать строки, вводимые в текстовые поля и текстовые представления, не проверяя значение сначала. Возможно, строка должна быть в определенном формате или значении (после того, как она преобразовывается в числовое значение), должен находиться в пределах определенного диапазона. Лучшие методы делегации для проверки вводимых строк textFieldShouldEndEditing: для текстовых полей и textViewShouldEndEditing: для текстовых представлений. Эти методы вызывают как раз перед текстовым полем или текстовым представлением оставляет первое состояние респондента. Возврат NO предотвращает это, и следовательно текстовый объект остается фокусом редактирования. Если вводимая строка недопустима, необходимо также вывести на экран предупреждение для информирования пользователя ошибки.

Перечисление 3-7 использует регулярное выражение, чтобы проверить, что строка, вводимая в поле «Social Security Number», соответствует формату для таких чисел.

Перечисление 3-7  , Проверяющее формат строки текстового поля с помощью регулярного выражения

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    if (textField == SSN) { // SSN is an outlet
        NSString *regEx = @"[0-9]{3}-[0-9]{2}-[0-9]{4}";
        NSRange r = [textField.text rangeOfString:regEx options:NSRegularExpressionSearch];
        if (r.location == NSNotFound) {
            UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error"
                message:@"Enter social security number in 'NNN-NN-NNNN' format"
                delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
            [av show];
            return NO;
        }
    }
        return YES;
}

Реализация textViewShouldEndEditing: в Перечислении 3-8 осуществляет символьный предел для текста, введенного в текстовом представлении.

Перечисление 3-8  , Проверяющее текстовую строку представления для допустимой длины

- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
      if (textView.text.length > 50) {
        UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error"
            message:@"You must enter less than 50 characters." delegate:self cancelButtonTitle:@"OK"
            otherButtonTitles:@"Clear", nil] autorelease];
        [av show];
        return NO;
    }
    return YES;
}

Делегат может также проверить каждый символ, поскольку он вводится в текстовое поле путем реализации textField:shouldChangeCharactersInRange:replacementString: метод. Код в Перечислении 3-9 проверяет что каждый вводимый символ (string) представляет цифру. (Вы могли достигнуть ту же цель путем указания a UIKeyboardTypeNumberPad клавиатура для текстового поля.)

Перечисление 3-9  , Проверяющее каждый символ, поскольку это вводится

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
    if ([string isEqualToString:@""]) return YES;
    if (textField.tag == SalaryFieldTag) {
        unichar c = [string characterAtIndex:0];
        if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:c]) {
            return YES;
        } else {
            return NO;
        }
    }
 
    return YES;
}

Можно также реализовать textField:shouldChangeCharactersInRange:replacementString: метод, чтобы предложить возможные завершения слова или исправления пользователю, поскольку они вводят текст.

Используя представления наложения в текстовых полях

Представления наложения являются маленькими представлениями, вставленными в левые и правые углы текстового поля. Они действуют как средства управления, когда пользователи касаются их (часто, они - кнопки), и действие на текущем содержании текстового поля. Поиск и установка закладки являются двумя общими задачами для представлений наложения, но другие возможны. Это представление наложения загружает веб-браузер с помощью (частичного) URL в текстовом поле:

../Art/overlay_view_2x.png

Для реализации представления наложения создайте представление размера, соответствующего в высоте текстового поля, и выскажите мнение соответственно размерное изображение. Если представление является кнопкой или другим управлением, укажите целевой объект, селектор действия и события управления инициированием. Обычно Вы хотите, чтобы представление наложения появилось, когда его текстовое поле является фокусом редактирования, поэтому присвойте его текстовому полю leftView или rightView свойство в делегате textFieldDidBeginEditing: метод. Можно управлять, когда представление наложения появляется во время сеанса редактирования — например, прежде чем пользователь начнет вводить текст или только после того, как пользователь начинает вводить текст — путем присвоения a UITextFieldViewMode постоянный к leftViewMode или rightViewMode свойство. Перечисление 3-10 иллюстрирует, как Вы могли бы реализовать представление наложения.

Перечисление 3-10  , Выводящее на экран наложение, просматривает в текстовом поле

- (void)textFieldDidBeginEditing:(UITextField *)textField {
     if (textField.tag == NameField && self.overlayButton) {
        textField.leftView = self.overlayButton;
        textField.leftViewMode = UITextFieldViewModeAlways;
    }
}
 
@dynamic overlayButton;
 
- (UIButton *)overlayButton {
    if (!overlayButton) {
        overlayButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
        UIImage *overlayImage = [UIImage imageNamed:@"bookmark.png"];
        if (overlayImage) {
            [overlayButton setImage:overlayImage forState:UIControlStateNormal];
            [overlayButton addTarget:self action:@selector(bookmarkTapped:)
                forControlEvents:UIControlEventTouchUpInside];
        }
    }
    return overlayButton;
}

Если Вы используете управление для представления наложения, несомненно, реализуют метод действия.

Для удаления представления наложения просто установите leftView или rightView свойство к nil в textFieldDidEndEditing: метод делегации, как в Перечислении 3-11.

Перечисление 3-11  , Удаляющее представление наложения

- (void)textFieldDidEndEditing:(UITextField *)textField {
 
    if (textField.tag == NameFieldTag) {
        textField.leftView = nil;
    }
    // remainder of implementation....
}

Отслеживание выбора в текстовых представлениях

textViewDidChangeSelection: метод UITextViewDelegate позволяет Вам отследить изменения в выборах, которые пользователь делает в текстовом представлении. Можно реализовать метод, чтобы получить выбранную подстроку и сделать что-то с ним. Перечисление 3-12 является причудливым примером, делающим все символы в выбранном верхнем регистре подстроки.

Перечисление 3-12  , Получающее выбранную подстроку и изменяющее его

- (void)textViewDidChangeSelection:(UITextView *)textView {
    NSRange r = textView.selectedRange;
    if (r.length == 0) {
        return;
    }
    NSString *selText = [textView.text substringWithRange:r];
    NSString *upString = [selText uppercaseString];
    NSString *newString = [textView.text stringByReplacingCharactersInRange:r withString:upString];
    textView.text = newString;
}