iOS. Приемы программирования Нахавандипур Вандад
• textColor — это свойство типа UIColor определяет цвет текста подписи.
• font — свойство типа UIFont задает шрифт, которым отображается текст подписи.
• adjustsFontSizeToFitWidth — это свойство типа BOOL. Если оно имеет значение YES, то размер шрифта будет изменяться таким образом, чтобы текст умещался в поле для подписи. Например, когда поле маленькое, а вы хотите записать на нем слишком большой текст. В этом случае среда времени исполнения автоматически уменьшит размер шрифта подписи, чтобы текст гарантированно поместился. Напротив, если для этого свойства задано значение NO, то программа будет действовать в соответствии с актуальной функцией заверстывания строк/слов/символов и текст отобразится не полностью — всего несколько слов.
Обсуждение
Подписи — одни из простейших компонентов пользовательского интерфейса, которые мы можем использовать в наших приложениях. Но при всей простоте их потенциал очень велик. Поэтому оформление подписей — очень важный фактор, значительно сказывающийся на удобстве использования интерфейса. Поэтому Apple предоставляет нам массу способов оформления экземпляров UILabel. Рассмотрим пример. Мы создаем простое приложение с единственным видом, в котором есть всего один контроллер вида. В центре экрана поместим простую надпись, выполненную огромным шрифтом, — она будет гласить: iOS SDK. Фон вида мы сделаем белым, а цвет тени, отбрасываемой подписью, — светло-серым. Мы убедимся, что тень находится ниже и правее подписи. На рис. 1.48 показан эффект, которого мы стремимся достичь.
Рис. 1.48. Оформление и отображение подписи на экране
А вот и код для этого:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong) UILabel *label;
@end
@implementation ViewController
— (void)viewDidLoad{
[super viewDidLoad];
self.label = [[UILabel alloc] init];
self.label.backgroundColor = [UIColor clearColor];
self.label.text = @"iOS SDK";
self.label.font = [UIFont boldSystemFontOfSize:70.0f];
self.label.textColor = [UIColor blackColor];
self.label.shadowColor = [UIColor lightGrayColor];
self.label.shadowOffset = CGSizeMake(2.0f, 2.0f);
[self.label sizeToFit];
self.label.center = self.view.center;
[self.view addSubview: self.label];
}
@end
См. также
Разделы 1.17, 1.26.
1.19. Прием пользовательского текстового ввода с помощью UITextField
Постановка задачи
Необходимо принимать через пользовательский интерфейс программы текст, вводимый пользователем.
Решение
Воспользуйтесь классом UITextField.
Обсуждение
Текстовое поле очень похоже на подпись тем, что в нем также можно отображать текстовую информацию. Но текстовое поле, в отличие от подписи, может принимать текстовый ввод и во время исполнения. На рис. 1.49 показаны два текстовых поля в разделе Twitter приложения Settings (Настройки) в iPhone.
Рис. 1.49. Текстовые поля, в которые можно вводить текст
В текстовом поле можно вводить и отображать только одну строку текста. Именно поэтому стандартная высота текстового поля, задаваемая по умолчанию, — всего 31 пункт. Эту высоту нельзя изменить в конструкторе интерфейса, но если вы создаете текстовое поле прямо в коде, то сделать это можно. Тем не менее при изменении высоты не изменяется количество строк, которые можно записать в текстовом поле, — строка всегда всего одна.
Чтобы определить наше текстовое поле, начнем работу с файла реализации контроллера вида:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong) UITextField *myTextField;
@end
@implementation ViewController
…
А потом создадим это текстовое поле:
— (void)viewDidLoad{
[super viewDidLoad];
CGRect textFieldFrame = CGRectMake(0.0f,
0.0f,
200.0f,
31.0f);
self.myTextField = [[UITextField alloc]
initWithFrame: textFieldFrame];
self.myTextField.borderStyle = UITextBorderStyleRoundedRect;
self.myTextField.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
self.myTextField.textAlignment = NSTextAlignmentCenter;
self.myTextField.text = @"Sir Richard Branson";
self.myTextField.center = self.view.center;
[self.view addSubview: self.myTextField];
}
Прежде чем подробно рассматривать код, взглянем на результат его выполнения (рис. 1.50).
При создании этого текстового поля мы использовали различные свойства класса UITextField:
• borderStyle — свойство имеет тип UITextBorderStyle и указывает, как должны отображаться границы текстового поля;
• contentVerticalAlignment — это значение типа UIControlContentVerticalAlignment, сообщающее текстовому полю, как текст должен отображаться по вертикали в границах этого поля. Если не выровнять текст по центру по вертикали, он по умолчанию отобразится в левом верхнем углу поля;
• textAlignment — это свойство имеет тип UITextAlignment и указывает выравнивание текста в текстовом поле по горизонтали. В данном примере текст выровнен в текстовом поле по центру и по горизонтали;
• text — это свойство доступно как для считывания, так и для записи. То есть можно не только получать из него информацию, но и записывать туда новые данные. Функция считывания возвращает текст, который в данный момент находится в текстовом поле, а функция записи задает для текстового поля то значение, которое вы в ней указываете.
Рис. 1.50. Простое текстовое поле, текст в котором выровнен по центру
Текстовое поле посылает сообщения-делегаты своему объекту-делегату. Такие сообщения отправляются, например, когда пользователь начинает изменять (редактировать) информацию в текстовом поле (как-либо изменяет его содержимое) и когда он прекращает взаимодействовать с полем (покидает его). Чтобы получать уведомления об этих событиях, задайте ваш объект в качестве значения свойства delegate текстового поля. Делегат текстового поля должен соответствовать протоколу UITextFieldDelegate, так что позаботимся об этом:
@interface ViewController () <UITextFieldDelegate>
@property (nonatomic, strong) UITextField *myTextField;
@end
@implementation ViewController
Нажав и удерживая клавишу Command, щелкните на протоколе UITextFieldDelegate в Xcode. Вы увидите методы, которыми позволяет управлять этот протокол. Рассмотрим эти методы, а также укажем, когда они вызываются.
• textFieldShouldBeginEditing: — возвращает логическое значение, сообщающее текстовому полю (текстовое поле является параметром этого метода), может ли пользователь редактировать содержащуюся в нем информацию (то есть разрешено это или нет). Возвратите здесь значение NO, если не хотите, чтобы пользователь изменял текст в этом поле. Метод запускается, как только пользователь касается этого поля, намереваясь его редактировать (при условии, что в поле допускается редактирование).
• textFieldDidBeginEditing: — вызывается, когда пользователь начинает редактировать текстовое поле. Этот метод запускается уже после того, как пользователь коснулся текстового поля, а метод делегата текстового поля textFieldShouldBeginEditing: возвратил значение YES, сообщив таким образом, что пользователь может редактировать содержимое этого поля.
• textFieldShouldEndEditing: — возвращает логическое значение, сообщающее текстовому полю, закончен текущий акт редактирования или нет. Этот метод запускается перед тем, как пользователь собирается покинуть текстовое поле, или после того, как статус активного объекта (First Responder) переходит к другому полю для ввода текста. Если возвратить NO от этого метода, то пользователь не сможет перейти в другое текстовое поле и начать вводить текст в него. Виртуальная клавиатура останется на экране.
• textFieldDidEndEditing: — вызывается, когда текущий акт редактирования конкретного текстового поля завершается. Это происходит, когда пользователь решает перейти к редактированию какого-то другого текстового поля или нажимает кнопку, предоставленную автором приложения, чтобы убрать с экрана клавиатуру, предназначенную для ввода текста в текстовое поле.
• textField: shouldChangeCharactersInRange: replacementString: — вызывается всякий раз, когда текст в текстовом поле изменяется. Возвращаемое значение этого метода — логическое. Если возвращается YES, это означает, что текст можно изменить. Если возвращается NO, то любые изменения текста в этом поле приняты не будут и даже не произойдут.
• textFieldShouldClear: — в каждом текстовом поле есть кнопка очистки — обычно это круглая кнопка с крестиком. Когда пользователь нажимает эту кнопку, все содержимое текстового поля автоматически стирается. Если вы предоставляете кнопку для очистки текста, но возвращаете от этого метода значение NO, то пользователь может подумать, что ваша программа не работает. Поэтому в данном случае вы должны отдавать себе отчет в том, что делаете. Если пользователь видит кнопку «Стереть», нажимает ее, а текст в поле не исчезает, это очень плохо характеризует программу.
• textFieldShouldReturn: — вызывается после того, как пользователь нажимает клавишу Return/Enter, пытаясь убрать клавиатуру с экрана. Текстовое поле должно быть присвоено этому методу в качестве активного элемента.
Объединим этот раздел с разделом 1.17 и создадим динамическую текстовую подпись под нашим текстовым полем. Кроме того, отобразим общее количество символов, введенных в текстовое поле. Начнем с файла реализации:
@interface ViewController () <UITextFieldDelegate>
@property (nonatomic, strong) UITextField *myTextField;
@property (nonatomic, strong) UILabel *labelCounter;
@end
@implementation ViewController
Теперь создадим текстовое поле с подписью и нужные нам методы делегата текстового поля. Обойдемся без реализации многих методов UITextFieldDelegate, так как в этом примере они нам не требуются:
— (void) calculateAndDisplayTextFieldLengthWithText:(NSString *)paramText{
NSString *characterOrCharacters = @"Characters";
if ([paramText length] == 1){
characterOrCharacters = @"Character";
}
self.labelCounter.text = [NSString stringWithFormat:@"%lu %@",
(unsigned long)[paramText length],
characterOrCharacters];
}
— (BOOL) textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
if ([textField isEqual: self.myTextField]){
NSString *wholeText =
[textField.text stringByReplacingCharactersInRange: range
withString: string];
[self calculateAndDisplayTextFieldLengthWithText: wholeText];
}
return YES;
}
— (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
— (void)viewDidLoad{
[super viewDidLoad];
CGRect textFieldFrame = CGRectMake(38.0f,
30.0f,
220.0f,
31.0f);
self.myTextField = [[UITextField alloc]
initWithFrame: textFieldFrame];
self.myTextField.delegate = self;
self.myTextField.borderStyle = UITextBorderStyleRoundedRect;
self.myTextField.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
self.myTextField.textAlignment = NSTextAlignmentCenter;
self.myTextField.text = @"Sir Richard Branson";
[self.view addSubview: self.myTextField];
CGRect labelCounterFrame = self.myTextField.frame;
labelCounterFrame.origin.y += textFieldFrame.size.height + 10;
self.labelCounter = [[UILabel alloc] initWithFrame: labelCounterFrame];
[self.view addSubview: self.labelCounter];
[self calculateAndDisplayTextFieldLengthWithText: self.myTextField.text];
}
Мы делаем важное вычисление в методе textField: shouldChangeCharactersInRange: replacementString:. Здесь мы объявляем и используем переменную wholeText. Когда вызывается этот метод, параметр replacementString указывает строку, которую пользователь ввел в текстовое поле. Вы, возможно, полагаете, что пользователь может вводить по одному символу в каждый момент времени, поэтому почему бы не присвоить данному полю значение char? Но не забывайте, что пользователь может вставить в текстовое поле целый фрагмент текста, по этой причине данный параметр должен быть строковым. Параметр shouldChangeCharactersInRange указывает место в текстовом поле, с которого пользователь начинает вводить текст. Итак, с помощью двух этих параметров мы создаем строку, которая сначала считывает весь текст из текстового поля, а потом использует заданный диапазон, чтобы разместить новый текст рядом со старым. Итак, получается, что вводимый нами текст будет появляться в поле после того, как метод textField: shouldChangeCharactersInRange: replacementString: возвратит YES. На рис. 1.51 показано, как приложение будет выглядеть в эмуляторе.
Рис. 1.51. Реагирование на сообщения-делегаты текстового поля
В текстовом поле может отображаться не только текст, но и подстановочные (джокерные) символы. Подстановочный текст отображается до того, как пользователь введет в это поле какой-нибудь собственный текст, пока свойство text текстового поля является пустым. В качестве подстановочного текста вы можете использовать любую строку, какую хотите, но лучше этим текстом подсказать пользователю, для ввода какой именно информации предназначено данное поле. Многие программисты указывают в подстановочном тексте, значения какого типа может принимать данное поле. Например, на рис. 1.49 в двух текстовых полях (для ввода имени пользователя и пароля) стоит подстановочный текст Required (Обязательно). Можно использовать свойство placeholder текстового поля для установки или получения актуального подстановочного текста:
CGRect textFieldFrame = CGRectMake(38.0f,
30.0f,
220.0f,
31.0f);
self.myTextField = [[UITextField alloc]
initWithFrame: textFieldFrame];
self.myTextField.delegate = self;
self.myTextField.borderStyle = UITextBorderStyleRoundedRect;
self.myTextField.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
self.myTextField.textAlignment = UITextAlignmentCenter;
self.myTextField.placeholder = @"Enter text here…";
[self.view addSubview: self.myTextField];
Результат показан на рис. 1.52.
У текстовых полей есть два очень приятных свойства, которые называются leftView и rightView. Они относятся к типу UIView и доступны как для чтения, так и для записи. Они проявляются, как понятно из названий, в левой (left) и правой (right) частях текстового поля, когда вы присваиваете им определенный вид. Первое свойство (левый вид) может использоваться, например, при показе курсов валют. В этом случае слева отображается курс валюты страны, в которой проживает пользователь. Поле с этими данными относится к типу UILabel. Вот как можно решить такую задачу:
Рис. 1.52. Подстановочный текст отображается, когда пользователь еще ничего не ввел в поле
UILabel *currencyLabel = [[UILabel alloc] initWithFrame: CGRectZero];
currencyLabel.text = [[[NSNumberFormatter alloc] init] currencySymbol];
currencyLabel.font = self.myTextField.font;
[currencyLabel sizeToFit];
self.myTextField.leftView = currencyLabel;
self.myTextField.leftViewMode = UITextFieldViewModeAlways;
Если просто присвоить вид свойству leftView или rightView текстового поля, то эти виды не появятся автоматически. То, когда они появятся на экране, зависит от режима, управляющего их внешним видом. Данный режим контролируется свойствами leftViewMode и rightViewMode соответственно. Эти режимы относятся к типу UITextFieldViewMode:
typedef NS_ENUM(NSInteger, UITextFieldViewMode) {
UITextFieldViewModeNever,
UITextFieldViewModeWhileEditing,
UITextFieldViewModeUnlessEditing,
UITextFieldViewModeAlways
}
Итак, например, если задать UITextFieldViewModeWhileEditing в качестве режима левого вида и присвоить ему значение, то этот вид будет отображаться только в то время, как пользователь редактирует текстовое поле. И наоборот, если задать здесь значение UITextFieldViewModeUnlessEditing, левый вид будет отображаться, только пока пользователь не редактирует текстовое поле. Как только редактирование начнется, левый вид исчезнет. Теперь запустим наш код в эмуляторе (рис. 1.53).
Рис. 1.53. Текстовое поле с левым видом
См. также
Раздел 1.17.
1.20. Отображение длинных текстовых строк с помощью UITextView
Постановка задачи
Требуется отображать в пользовательском интерфейсе несколько строк текста с возможностью прокрутки.
Решение
Воспользуйтесь классом UITextView.
Обсуждение
Класс UITextView позволяет отображать несколько строк текста и создавать прокручиваемое содержимое. Это означает, что если содержимое не умещается в границах текстового вида, то внутренние компоненты этого текстового вида позволяют пользователю прокручивать текст вверх и вниз и просматривать различные его части. В качестве примера текстового вида, входящего в приложение iOS, рассмотрим программу Notes (Блокнот) в iPhone (рис. 1.54).
Рис. 1.54. Программа Notes (Блокнот) в iPhone, здесь текст отображается в текстовом виде
Создадим текстовый вид и посмотрим, как он работает. Для начала определим текстовый вид в файле реализации контроллера нашего вида:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong) UITextView *myTextView;
@end
implementation ViewController
Далее необходимо создать сам текстовый вид. Мы сделаем текстовый вид таким же по размеру, как и вид контроллера вида:
— (void)viewDidLoad{
[super viewDidLoad];
self.myTextView = [[UITextView alloc] initWithFrame: self.view.bounds];
self.myTextView.text = @"Some text here…";
self.myTextView.contentInset = UIEdgeInsetsMake(10.0f, 0.0f, 0.0f, 0.0f);
self.myTextView.font = [UIFont systemFontOfSize:16.0f];
[self.view addSubview: self.myTextView];
}
Запустим приложение в эмуляторе iOS и посмотрим, как оно выглядит (рис. 1.55).
Рис. 1.55. Текстовый вид, занимающий все экранное пространство
Если коснуться текстового поля пальцем, то можно увидеть, как снизу всплывает виртуальная клавиатура. Она довольно крупная и закрывает текстовый вид почти наполовину. То есть если пользователь начнет вводить текст и дойдет примерно до середины окна по вертикали, весь остальной текст, который будет вводиться, окажется заслоненным клавиатурой (рис. 1.56).
Чтобы избежать такой ситуации, необходимо слушать определенные уведомления:
• UIKeyboardWillShowNotification — система выдает такое уведомление всякий раз, когда клавиатура выводится на экран для работы с каким-либо компонентом: текстовым полем, текстовым видом и т. д.;
• UIKeyboardDidShowNotification — система выдает такое уведомление, когда клавиатура отобразится целиком;
• UIKeyboardWillHideNotification — система выдает такое уведомление перед тем, как клавиатура скроется из вида;
Рис. 1.56. Клавиатура, наполовину занимающая текстовый вид