Текст книги "iOS. Приемы программирования"
Автор книги: Вандад Нахавандипур
Жанр: Зарубежная компьютерная литература, Зарубежная литература
сообщить о неприемлемом содержимом
Текущая страница: 6 (всего у книги 59 страниц)
Раздел 1.6.
1.8. Группирование компактных параметров с помощью UISegmentedControl
Постановка задачиТребуется предложить пользователям на выбор несколько параметров, из которых они могут выбирать. Пользовательский интерфейс должен оставаться компактным, простым и легким для понимания.
РешениеИспользуйте класс UISegmentedControl. Пример работы с этим классом показан на рис. 1.22.
Рис. 1.22. Сегментированный элемент управления, в котором отображаются четыре параметра
ОбсуждениеСегментированный элемент управления – это сущность, позволяющая отображать в компактном пользовательском интерфейсе наборы параметров, из которых пользователь может выбирать нужный. Чтобы отобразить сегментированный элемент управления, создайте экземпляр класса UISegmentedControl. Начинаем работу с файла реализации (.m) нашего контроллера вида:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong) UISegmentedControl *mySegmentedControl;
@end
@implementation ViewController
…
Создаем сегментированный элемент управления в методе viewDidLoad контроллера нашего вида:
– (void)viewDidLoad{
[super viewDidLoad];
NSArray *segments = [[NSArray alloc] initWithObjects:
@"iPhone",
@"iPad",
@"iPod",
@"iMac", nil];
self.mySegmentedControl = [[UISegmentedControl alloc]
initWithItems: segments];
self.mySegmentedControl.center = self.view.center;
[self.view addSubview: self.mySegmentedControl];
}
Чтобы представить разные параметры, которые будут предлагаться на выбор в нашем сегментированном элементе управления, мы используем обычный массив строк. Такой элемент управления инициализируется с помощью метода initWithObjects:. Потом передаем сегментированному элементу управления массив строк и изображений. Результат будет как на рис. 1.22.
Теперь пользователь может выбрать в сегментированном элементе управления один из параметров. Допустим, он выбирает iPad. Тогда пользовательский интерфейс сегментированного элемента управления изменится и покажет пользователю, какой параметр будет выбран. Получится такое изображение, как на рис. 1.23.
Рис. 1.23. Пользователь выбрал один из вариантов в сегментированном элементе управления
Возникает вопрос: как узнать, что пользователь выбрал в сегментированном элементе управления новый параметр? Ответ прост. Как и при работе с UISwitch или UISlider, применяется метод addTarget: action: forControlEvents: сегментированного элемента управления, к которому добавляется цель. Для параметра forControlEvents нужно задать значение UIControlEventValueChanged, так как именно это событие запускается, когда пользователь выбирает в сегментированном элементе управления новый параметр:
– (void) segmentChanged:(UISegmentedControl *)paramSender{
if ([paramSender isEqual: self.mySegmentedControl]){
NSInteger selectedSegmentIndex = [paramSender selectedSegmentIndex];
NSString *selectedSegmentText =
[paramSender titleForSegmentAtIndex: selectedSegmentIndex];
NSLog(@"Segment %ld with %@ text is selected",
(long)selectedSegmentIndex,
selectedSegmentText);
}
}
– (void)viewDidLoad{
[super viewDidLoad];
NSArray *segments = [[NSArray alloc] initWithObjects:
@"iPhone",
@"iPad",
@"iPod",
@"iMac", nil];
self.mySegmentedControl = [[UISegmentedControl alloc]
initWithItems: segments];
self.mySegmentedControl.center = self.view.center;
[self.view addSubview: self.mySegmentedControl];
[self.mySegmentedControl addTarget: self
action:@selector(segmentChanged:)
forControlEvents: UIControlEventValueChanged];
}
Если пользователь начинает выбирать слева и выбирает каждый параметр (см. рис. 1.22) до правого края, на консоль будет выведен следующий текст:
Segment 0 with iPhone text is selected
Segment 1 with iPad text is selected
Segment 2 with iPod text is selected
Segment 3 with iMac text is selected
Как видите, мы использовали метод selectedSegmentIndex сегментированного элемента управления, чтобы найти индекс варианта, выбранного в настоящий момент. Если ни один из элементов не выбран, метод возвращает значение –1. Кроме того, мы использовали метод titleForSegmentAtIndex:. Просто передаем этому методу индекс параметра, выбранного в сегментированном элементе управления, а сегментированный элемент управления возвратит текст, соответствующий этому параметру. Ведь просто, правда?
Как вы, вероятно, заметили, как только пользователь отмечает один из параметров в сегментированном элементе управления, этот параметр выбирается и остается выбранным, как показано на рис. 1.23. Если вы хотите, чтобы пользователь выбрал параметр, но кнопка этого параметра не оставалась нажатой, а возвращалась к исходной форме (так сказать, «отщелкивалась обратно», как и обычная кнопка), то нужно задать для свойства momentary сегментированного элемента управления значение YES:
self.mySegmentedControl.momentary = YES;
Одна из самых приятных особенностей сегментированных элементов управления заключается в том, что они могут содержать не только текст, но и изображения. Для этого нужно просто использовать метод-инициализатор initWithObjects: класса UISegmentedControl и передать с этим методом те строки и изображения, которые будут применяться при реализации соответствующего пользовательского интерфейса:
– (void)viewDidLoad{
[super viewDidLoad];
NSArray *segments = [[NSArray alloc] initWithObjects:
@"iPhone",
[UIImage imageNamed:@"iPad"],
@"iPod",
@"iMac",
];
self.mySegmentedControl = [[UISegmentedControl alloc]
initWithItems: segments];
CGRect segmentedFrame = self.mySegmentedControl.frame;
segmentedFrame.size.height = 128.0f;
segmentedFrame.size.width = 300.0f;
self.mySegmentedControl.frame = segmentedFrame;
self.mySegmentedControl.center = self.view.center;
[self.view addSubview: self.mySegmentedControl];
}
В данном примере файл iPad.png – это просто миниатюрное изображение «айпада», добавленное в наш проект.
В iOS 7 Apple отказалась от использования свойства segmentedControlStyle класса UISegmentedControl, поэтому теперь сегментированные элементы управления имеют всего один стиль, задаваемый по умолчанию. Мы больше не можем изменять этот стиль.
1.9. Представление видов и управление ими с помощью UIViewController
Постановка задачиНеобходимо иметь возможность переключаться между видами в вашем приложении.
РешениеВоспользуйтесь классом UIViewController.
ОбсуждениеСтратегия разработки для iOS, предложенная Apple, предполагает использование паттерна «модель – вид – контроллер» (MVC) и соответствующее разделение задач. Виды – это элементы, отображаемые для пользователя, а модель – это абстракция с данными, которыми управляет приложение. Контроллер – это перемычка, соединяющая модель и вид. Контроллер (в данном случае речь идет о контроллере вида) управляет отношениями между видом и моделью. Почему же этими отношениями не занимается вид? Ответ довольно прост: если бы мы возлагали эти задачи на вид, код вида становился бы очень запутанным. Кроме того, такой подход тесно связывал бы виды с моделью, что не очень хорошо.
Контроллеры видов можно загружать из файлов XIB (для использования с конструктором интерфейсов) или просто создавать с помощью программирования. Сначала рассмотрим, как создать контроллер вида, не пользуясь файлом XIB.
Контроллеры видов удобно создавать в Xcode. Теперь, когда вы уже создали шаблон приложения с помощью шаблона Empty Application (Пустое приложение), выполните следующие шаги, чтобы создать новый контроллер вида для вашего приложения.
1. В Xcode перейдите в меню File (Файл) и там выберите New-New File (Новый– Новый файл).
2. В диалоговом окне New File (Новый файл) убедитесь, что слева выбраны категория iOS и подкатегория Cocoa Touch. Когда сделаете это, выберите класс UIViewController в правой части диалогового окна, а затем нажмите Next (Далее) (рис. 1.24).
Рис. 1.24. Подкласс нового контроллера вида
3. На следующем экране убедитесь, что в текстовом поле Subclass (Подкласс) указано UIViewController, а также что сняты флажки Targeted for iPad (Разработка для iPad) и With XIB for user interface (Использовать файл XIB для пользовательского интерфейса). Именно такая ситуация показана на рис. 1.25. Нажмите Next (Далее).
Рис. 1.25. Собственный контроллер вида, без использования класса XIB
4. На следующем экране (Save as (Сохранить как)) назовите файл контроллера вида RootViewController и нажмите Save (Сохранить) (рис. 1.26).
Рис. 1.26. Сохранение контроллера вида без использования файла XIB
5. Теперь найдем файл реализации (.m) делегата приложения, который обычно называется AppDelegate.m. В этом файле объявим свойство типа ViewController:
#import «AppDelegate.h»
#import «ViewController.h»
@interface AppDelegate ()
@property (nonatomic, strong) ViewController *viewController;
@end
@implementation AppDelegate
…
6. Найдем в файле реализации метод application: didFinishLaunchingWithOptions:, относящийся к делегату приложения, инстанцируем контроллер вида и добавим его в наше окно как корневой контроллер вида:
– (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.viewController = [[ViewController alloc] initWithNibName: nil
bundle: nil];
self.window = [[UIWindow alloc]
initWithFrame: [[UIScreen mainScreen] bounds]];
/* Делаем наш контроллер вида корневым контроллером вида */
self.window.rootViewController = self.viewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Теперь снова попробуем запустить приложение в эмуляторе. На экране увидим вид, имеющий ровный белый цвет. Поздравляю: вы только что создали контроллер вида, и теперь у вас есть доступ не только к контроллеру вида, но и к самому объекту этого вида.
Если при создании контроллера вида (см. рис. 1.25) установить флажок With XIB for user interface (Использовать файл XIB для пользовательского интерфейса), то Xcode также сгенерирует файл XIB. В таком случае вам придется загрузить контроллер вашего вида из этого файла XIB, передав в параметр initWithNibName метода initWithNibName: bundle: контроллера вида полное имя файла XIB:
– (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.viewController = [[ViewController alloc]
initWithNibName:@"ViewController"
bundle: nil];
self.window = [[UIWindow alloc]
initWithFrame: [[UIScreen mainScreen] bounds]];
/* Делаем наш контроллер вида корневым контроллером вида */
self.window.rootViewController = self.viewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Если вы все же создали файл XIB, подготавливая контроллер вашего вида, этот файл теперь можно выбрать в Xcode и смастерить пользовательский интерфейс в конструкторе интерфейсов.
См. такжеРаздел 1.0.
1.10. Предоставление возможностей совместного использования информации с применением UIActivityViewController
Постановка задачиВнутри вашего приложения вы хотите предоставить пользователям возможность обмениваться контентом с их друзьями. Для этого предполагается использовать интерфейс, подобный тому, что показан на рис. 1.27. В этом интерфейсе предоставляются различные возможности совместного использования информации, имеющиеся в iOS, – например, через Facebook и Twitter.
РешениеСоздайте экземпляр класса UIActivityViewController и реализуйте совместное использование контента в этом классе так, как рассказано в подразделе «Обсуждение» данного раздела.
Экземпляры класса UIActivityViewController на iPhone следует представлять модально, а на iPad – на вспомогательных экранах. Более подробно о вспомогательных экранах рассказано в разделе 1.29.
Рис. 1.27. Контроллер вида для обмена информацией, открытый на устройстве с iOS
ОбсуждениеВ iOS существует масса возможностей совместного использования информации. Все они реализованы в ядре операционной системы. Например, такой неотъемлемой частью ядра сейчас является интеграция с Twitter и Facebook. Вы можете делиться практически любым контентом из этих сетей, находясь где угодно. Сторонние приложения наподобие того, которое собираемся написать мы, также могут использовать присущие iOS возможности совместного использования информации, не углубляясь в низкоуровневые детали сервисов и базовую организацию этих возможностей в iOS. Красота идеи заключается в том, что вам достаточно всего лишь указать, чем вы хотите поделиться, после чего iOS сама подберет возможности совместного использования, обеспечивающие обработку такой информации. Например, если вы хотите совместно использовать изображения и текст, то iOS предложит вам гораздо больше возможностей, чем если бы вы хотели поделиться аудиофайлом.
Совместное использование данных в iOS организовано очень просто. Для обеспечения такой работы вам всего лишь потребуется инстанцировать класс UIActivityViewController с помощью его метода-инициализатора initWithActivityItems: applicationActivities:. Вот какие параметры принимает этот метод:
• initWithActivityItems – массив элементов, которые предполагается совместно использовать. Это могут быть экземпляры NSString, UIImage или экземпляры любых других заказных классов, соответствующих протоколу UIActivityItemSource. Далее мы детально рассмотрим этот протокол;
• applicationActivities – массив экземпляров UIActivity, представляющих собой функции, поддерживаемые в вашем приложении. Например, здесь вы можете указать, может ли приложение организовать собственный механизм совместного использования изображений и строк. Пока мы не будем детально рассматривать этот параметр и просто передадим nil в качестве его значения. Так мы сообщаем iOS, что собираемся пользоваться только системными возможностями совместного использования.
Итак, допустим, что у нас есть текстовое поле, где пользователь может ввести текст, который затем будет использоваться совместно. Рядом с этим полем будет находиться кнопка Share (Поделиться). Когда пользователь нажимает кнопку Share, вы просто передаете текст, находящийся в текстовом поле, вашему экземпляру класса UIActivityViewController. Далее приведен соответствующий код. Мы пишем этот код для iPhone, поэтому представим контроллер вида с этой активностью как модальный контроллер вида.
Поскольку мы помещаем в нашем контроллере вида текстовое поле, нам необходимо обеспечить обработку его делегатных сообщений, в особенности тех, что поступают от метода textFieldShouldReturn: из протокола UITextFieldDelegate. Следовательно, мы собираемся выбрать контроллер вида в качестве делегата текстового поля. Кроме того, прикрепим к кнопке Share (Поделиться) метод действия. Когда эта кнопка будет нажата, нам потребуется убедиться, что в текстовом поле есть какая-то информация, которой можно поделиться. Если ее там не окажется, мы просто отобразим для пользователя окно с предупреждением, в котором сообщим, что не можем предоставить содержимое текстового поля для совместного использования. Если в текстовом поле окажется какой-либо текст, мы выведем на экран экземпляр класса UIActivityViewController.
Итак, начнем с файла реализации контроллера вида и определим компоненты пользовательского интерфейса:
@interface ViewController () <UITextFieldDelegate>
@property (nonatomic, strong) UITextField *textField;
@property (nonatomic, strong) UIButton *buttonShare;
@property (nonatomic, strong) UIActivityViewController *activityViewController;
@end
…
Затем напишем для контроллера вида два метода, каждый из которых будет способен создать один из компонентов пользовательского интерфейса и поместить этот компонент в окно контроллера вида. Один метод будет создавать текстовое поле, а другой – кнопку рядом с этим полем:
– (void) createTextField{
self.textField = [[UITextField alloc] initWithFrame: CGRectMake(20.0f,
35.0f,
280.0f,
30.0f)];
self.textField.translatesAutoresizingMaskIntoConstraints = NO;
self.textField.borderStyle = UITextBorderStyleRoundedRect;
self.textField.placeholder = @"Enter text to share…";
self.textField.delegate = self;
[self.view addSubview: self.textField];
}
– (void) createButton{
self.buttonShare = [UIButton buttonWithType: UIButtonTypeRoundedRect];
self.buttonShare.translatesAutoresizingMaskIntoConstraints = NO;
self.buttonShare.frame = CGRectMake(20.0f, 80.0f, 280.0f, 44.0f);
[self.buttonShare setTitle:@"Share" forState: UIControlStateNormal];
[self.buttonShare addTarget: self
action:@selector(handleShare:)
forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview: self.buttonShare];
}
Когда эта работа будет завершена, нам останется всего лишь вызвать два этих метода в методе viewDidLoad нашего контроллера вида. Таким образом мы правильно разместим компоненты пользовательского интерфейса в окне контроллера вида:
– (void)viewDidLoad{
[super viewDidLoad];
[self createTextField];
[self createButton];
}
В методе textFieldShouldReturn: мы просто убираем с экрана клавиатуру, чтобы отказаться от активного состояния текстового поля. Это просто означает, что если пользователь редактировал текст в текстовом поле, а затем нажал клавишу Enter, то клавиатура должна исчезнуть с экрана. Не забывайте, что только что написанный метод createTextField задает наш контроллер вида в качестве делегата текстового поля. Поэтому потребуется реализовать упомянутый метод следующим образом:
– (BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
Последний, но немаловажный элемент – это метод-обработчик нашей кнопки. Как мы уже видели, метод createButton создает для нас кнопку и выбирает метод handleShare: для обработки действия-касания (нажатия) в рамках работы кнопки. Напишем этот метод:
– (void) handleShare:(id)paramSender{
if ([self.textField.text length] == 0){
NSString *message = @"Please enter a text and then press Share";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle: nil
message: message
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alertView show];
return;
}
self.activityViewController = [[UIActivityViewController alloc]
initWithActivityItems:@[self.textField.text]
applicationActivities: nil];
[self presentViewController: self.activityViewController
animated: YES
completion: ^{
/* Пока ничего не делаем */
}];
}
Теперь, если запустить приложение, ввести в текстовое поле какой-либо текст, а затем нажать кнопку Share (Поделиться), мы получим результат, похожий на то, что изображено на рис. 1.28.
Рис. 1.28. Возможности совместного использования экземпляра строки, которым мы пытаемся поделиться
Вы можете выводить на экран параметры совместного использования уже вместе с контроллером вида. Метод viewDidAppear вашего контроллера вида будет вызываться, когда контроллер вида отобразится на экране и гарантированно окажется в иерархии видов вашего приложения. Это означает, что теперь вы сможете отобразить и другие виды поверх вашего контроллера вида.
См. такжеНе пытайтесь представить контроллер вида для работы с функциями в методе viewDidLoad контроллера вида. На данном этапе подготовки приложения окно контроллера вашего вида еще не прикреплено к иерархии видов приложения, поэтому такая попытка ни к чему не приведет. Чтобы модальные виды работали, ваш вид должен быть частью такой иерархии. Поэтому необходимо представлять контроллер вида для обмена информацией в методе viewDidAppear контроллера вида.
Раздел 1.29.
1.11. Предоставление специальных возможностей совместного использования данных с применением UIActivityViewController
Постановка задачиВы хотите включить вашу программу в список тех приложений, которые способны обеспечивать в iOS совместную работу с данными и отображать эту программу в списке доступных функций, выстраиваемом в соответствующем контроллере вида (см. рис. 1.27).
Подобные возможности могут понадобиться вам, например, при работе с текстовым редактором. Когда пользователь нажимает кнопку Share (Поделиться), в контроллере вида с функцией должен появиться специальный элемент, в котором написано: Archive (Архивировать). Когда пользователь нажмет кнопку Archive (Архивировать), текст в редактируемой области вашего приложения будет передан специальной функции, а затем ваша функция сможет заархивировать этот текст в файловой системе на устройстве с iOS.
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.