Современная электронная библиотека ModernLib.Net

Бестселлеры O`Reilly - iOS. Приемы программирования

ModernLib.Net / Программирование / Вандад Нахавандипур / iOS. Приемы программирования - Чтение (Ознакомительный отрывок) (стр. 6)
Автор: Вандад Нахавандипур
Жанр: Программирование
Серия: Бестселлеры O`Reilly

 

 


[self.slider setMinimumTrackImage: [self minimumTrackImage]

forState: UIControlStateNormal];


/* Изменяем изображение ползунка для обоих возможных состояний ползунка: когда

пользователь его касается и когда не касается */

[self.slider setThumbImage: [UIImage imageNamed:@"Thumb"]

forState: UIControlStateNormal];

[self.slider setThumbImage: [UIImage imageNamed:@"Thumb"]

forState: UIControlStateHighlighted];


/* Изменяем изображение для области максимальных значений */

[self.slider setMaximumTrackImage: [self maximumTrackImage]

forState: UIControlStateNormal];


/* Изменяем изображение, соответствующее максимальному значению */

[self.slider setMaximumValueImage: [UIImage imageNamed:@"MaximumValue"]];

}

Ползунок в iOS 7 выглядит совершенно иначе, нежели в более ранних версиях. Как вы догадываетесь, этот элемент стал очень прямолинейным и тонким на вид. Высота максимальной и минимальной отметок на шкале в iOS 7 составляет всего 1 точку, поэтому задавать для этих элементов специальные изображения абсолютно бесполезно – скорее всего, получится некрасиво. Поэтому для оформления этих элементов UISlider в iOS 7 рекомендуется оперировать лишь оттенками, но не присваивать элементу никаких изображений.

<p>См. также</p>

Раздел 1.6.

1.8. Группирование компактных параметров с помощью UISegmentedControl

<p>Постановка задачи</p>

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

<p>Решение</p>

Используйте класс UISegmentedControl. Пример работы с этим классом показан на рис. 1.22.


Рис. 1.22. Сегментированный элемент управления, в котором отображаются четыре параметра

<p>Обсуждение</p>

Сегментированный элемент управления – это сущность, позволяющая отображать в компактном пользовательском интерфейсе наборы параметров, из которых пользователь может выбирать нужный. Чтобы отобразить сегментированный элемент управления, создайте экземпляр класса 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

<p>Постановка задачи</p>

Необходимо иметь возможность переключаться между видами в вашем приложении.

<p>Решение</p>

Воспользуйтесь классом UIViewController.

<p>Обсуждение</p>

Стратегия разработки для 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 и смастерить пользовательский интерфейс в конструкторе интерфейсов.

<p>См. также</p>

Раздел 1.0.

1.10. Предоставление возможностей совместного использования информации с применением UIActivityViewController

<p>Постановка задачи</p>

Внутри вашего приложения вы хотите предоставить пользователям возможность обмениваться контентом с их друзьями. Для этого предполагается использовать интерфейс, подобный тому, что показан на рис. 1.27. В этом интерфейсе предоставляются различные возможности совместного использования информации, имеющиеся в iOS, – например, через Facebook и Twitter.

<p>Решение</p>

Создайте экземпляр класса UIActivityViewController и реализуйте совместное использование контента в этом классе так, как рассказано в подразделе «Обсуждение» данного раздела.

Экземпляры класса UIActivityViewController на iPhone следует представлять модально, а на iPad – на вспомогательных экранах. Более подробно о вспомогательных экранах рассказано в разделе 1.29.

Рис. 1.27. Контроллер вида для обмена информацией, открытый на устройстве с iOS

<p>Обсуждение</p>

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

@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 контроллера вида.

<p>См. также</p>

Раздел 1.29.

1.11. Предоставление специальных возможностей совместного использования данных с применением UIActivityViewController

<p>Постановка задачи</p>

Вы хотите включить вашу программу в список тех приложений, которые способны обеспечивать в iOS совместную работу с данными и отображать эту программу в списке доступных функций, выстраиваемом в соответствующем контроллере вида (см. рис. 1.27).

Подобные возможности могут понадобиться вам, например, при работе с текстовым редактором. Когда пользователь нажимает кнопку Share (Поделиться), в контроллере вида с функцией должен появиться специальный элемент, в котором написано: Archive (Архивировать). Когда пользователь нажмет кнопку Archive (Архивировать), текст в редактируемой области вашего приложения будет передан специальной функции, а затем ваша функция сможет заархивировать этот текст в файловой системе на устройстве с iOS.

<p>Решение</p>

Создайте класс типа UIActivity. Иными словами, произведите подкласс от этого класса и дайте новоиспеченному классу любое устраивающее вас имя. Экземпляры подклассов этого класса можно будет передавать методу-инициализатору initWithActivityItems: applicationActivities:, относящемуся к классу UIActivityViewController. Если эти экземпляры реализуют все необходимые методы класса UIActivity, то iOS отобразит их в контроллере вида с функцией.

<p>Обсуждение</p>

Первый параметр метода initWithActivityItems: applicationActivities: принимает значения различных типов, в частности строки, числа, изображения и т. д. – фактически любые объекты. Если вы представите в параметре initWithActivityItems контроллер активности с массивом объектов произвольных типов, iOS просмотрит все доступные в системе функции – например, для работы с Facebook и Twitter – и предложит пользователю выбрать такую функцию, которая лучше всего отвечает его нуждам. После того как пользователь выберет функцию, iOS передаст тип объектов, находящихся в вашем массиве, в зарегистрированную системную функцию, выбранную пользователем. Затем такие функции смогут проверять тип объектов, которые вы собираетесь предоставлять в совместное пользование, и решать, может ли та или иная функция обработать такие объекты или нет. Функции передают такую информацию системе iOS посредством особого метода, реализуемого в их классах.


  • Страницы:
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15