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

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

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

 

 


Работая с данным разделом, выполните шаги, перечисленные в подразделе «Создание и запуск вашего первого приложения для iOS» раздела 1.0 данной главы и создайте пустое приложение. Потом проделайте шаги, описанные в разделе 1.12, и добавьте в делегат вашего приложения навигационный контроллер.

Чтобы создать кнопку для навигационной панели, необходимо сделать следующее.

1. Создать экземпляр класса UIBarButtonItem.

2. Добавить получившуюся кнопку на навигационную панель, воспользовавшись свойством navigationItem, относящимся к контроллеру вида. Свойство navigationItem позволяет взаимодействовать с навигационной панелью. Само это свойство может принимать еще два свойства: rightBarButtonItem и leftBarButtonItem. Оба они относятся к типу UIBarButtonItem.

Теперь рассмотрим пример, в котором добавим кнопку в правую часть нашей навигационной панели. На этой кнопке будет написано Add (Добавить):


– (void) performAdd:(id)paramSender{

NSLog(@"Action method got called.");

}


– (void)viewDidLoad{

[super viewDidLoad];


self.title = @"First Controller";


self.navigationItem.rightBarButtonItem =

[[UIBarButtonItem alloc] initWithTitle:@"Add"

style: UIBarButtonItemStylePlain

target: self

action:@selector(performAdd:)];

}


Если сейчас запустить приложение, появится картинка, примерно как на рис. 1.37.


Рис. 1.37. Навигационная кнопка, добавленная на навигационную панель


Пока все просто. Но если вы регулярно пользуетесь iOS, то, вероятно, заметили, что в системных приложениях iOS применяется готовая конфигурация и кнопка Add (Добавить) там выглядит иначе. На рис. 1.38 показан пример из раздела Alarm (Будильник) приложения Clock (Часы) для iPhone. Обратите внимание на кнопку + в верхней правой части навигационной панели.


Рис. 1.38. Правильный способ создания кнопки Add (Добавить)


Оказывается, в SDK iOS можно создавать системные кнопки. Это делается с помощью метода-инициализатора nitWithBarButtonSystemItem: target: action:, относящегося к классу UIBarButtonItem:


– (void) performAdd:(id)paramSender{

NSLog(@"Action method got called.");

}


– (void)viewDidLoad{

[super viewDidLoad];

self.title = @"First Controller";


self.navigationItem.rightBarButtonItem =

[[UIBarButtonItem alloc]

initWithBarButtonSystemItem: UIBarButtonSystemItemAdd

target: self

action:@selector(performAdd:)];

}


В результате получится именно то, чего мы добивались (рис. 1.39).

Первый параметр метода-инициализатора initWithBarButtonSystemItem: target: action:, относящегося к навигационной кнопке, может принимать в качестве параметров любые значения из перечня UIBarButtonSystemItem:


Рис. 1.39. Системная кнопка Add (Добавить)


typedef NS_ENUM(NSInteger, UIBarButtonSystemItem) {

UIBarButtonSystemItemDone,

UIBarButtonSystemItemCancel,

UIBarButtonSystemItemEdit,

UIBarButtonSystemItemSave,

UIBarButtonSystemItemAdd,

UIBarButtonSystemItemFlexibleSpace,

UIBarButtonSystemItemFixedSpace,

UIBarButtonSystemItemCompose,

UIBarButtonSystemItemReply,

UIBarButtonSystemItemAction,

UIBarButtonSystemItemOrganize,

UIBarButtonSystemItemBookmarks,

UIBarButtonSystemItemSearch,

UIBarButtonSystemItemRefresh,

UIBarButtonSystemItemStop,

UIBarButtonSystemItemCamera,

UIBarButtonSystemItemTrash,

UIBarButtonSystemItemPlay,

UIBarButtonSystemItemPause,

UIBarButtonSystemItemRewind,

UIBarButtonSystemItemFastForward,

#if __IPHONE_3_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED

UIBarButtonSystemItemUndo,

UIBarButtonSystemItemRedo,

#endif

#if __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED

UIBarButtonSystemItemPageCurl,

#endif

};


Один из самых интересных инициализаторов из класса UIBarButtonItem – метод initWithCustomView:. В качестве параметра этот метод может принимать любой вид, то есть мы даже можем добавить на навигационную панель в качестве навигационной кнопки UISwitch (см. раздел 1.2). Это будет выглядеть не очень красиво, но мы просто попробуем:


– (void) switchIsChanged:(UISwitch *)paramSender{

if ([paramSender isOn]){

NSLog(@"Switch is on.");

} else {

NSLog(@"Switch is off.");

}

}


– (void)viewDidLoad{

[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

self.title = @"First Controller";


UISwitch *simpleSwitch = [[UISwitch alloc] init];

simpleSwitch.on = YES;

[simpleSwitch addTarget: self

action:@selector(switchIsChanged:)

forControlEvents: UIControlEventValueChanged];


self.navigationItem.rightBarButtonItem =

[[UIBarButtonItem alloc] initWithCustomView: simpleSwitch];

}


Вот что получается (рис. 1.40).


Рис. 1.40. Переключатель, добавленный на навигационную панель


На навигационной панели можно создавать очень и очень занятные кнопки. Просто взгляните, что делает Apple со стрелками, направленными вверх и вниз, расположенными в правом верхнем углу на рис. 1.36. А почему бы нам тоже так не сделать? Впечатление такое, как будто в кнопку встроен сегментированный элемент управления (см. раздел 1.8). Итак, нам нужно создать такой элемент управления с двумя сегментами, добавить его на навигационную кнопку и, наконец, поставить эту кнопку на навигационную панель. Начнем:


– (void) segmentedControlTapped:(UISegmentedControl *)paramSender{

switch (paramSender.selectedSegmentIndex){

case 0:{

NSLog(@"Up");

break;

}

case 1:{

NSLog(@"Down");

break;

}

}


}


– (void)viewDidLoad{

[super viewDidLoad];


self.title = @"First Controller";


NSArray *items = @[

@"Up",

@"Down"

];


UISegmentedControl *segmentedControl = [[UISegmentedControl alloc]

initWithItems: items];


segmentedControl.momentary = YES;


[segmentedControl addTarget: self

action:@selector(segmentedControlTapped:)

forControlEvents: UIControlEventValueChanged];


self.navigationItem.rightBarButtonItem =

[[UIBarButtonItem alloc] initWithCustomView: segmentedControl];

}


На рис. 1.41 показано, что должно получиться в итоге.


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


Элемент navigationItem любого контроллера вида имеет еще два замечательных метода:

• setRightBarButtonItem: animated: – задает правую кнопку навигационной панели;

• setLeftBarButtonItem: animated: – определяет левую кнопку навигационной панели.

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


UIBarButtonItem *rightBarButton =

[[UIBarButtonItem alloc] initWithCustomView: segmentedControl];


[self.navigationItem setRightBarButtonItem: rightBarButton
animated: YES];

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

Подраздел «Создание и запуск вашего первого приложения для iOS» раздела 1.0 данной главы. Разделы 1.2, 1.8, 1.12.

1.16. Представление контроллеров, управляющих несколькими видами, с помощью UITabBarController

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

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

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

Используйте класс UITabBarController.

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

Если вы пользуетесь iPhone как будильником, то, разумеется, замечали на экране панель вкладок. Взгляните на рис. 1.38. В нижней части экрана расположены значки, которые называются World Clock (Мировое время), Alarm (Будильник), Stopwatch (Секундомер) и Timer (Таймер). Вся черная полоса в нижней части экрана – это панель вкладок, а вышеупомянутые ярлыки – ее элементы.

Панель вкладок – это контейнерный контроллер. Это значит, что мы создаем экземпляры UITabBarController и добавляем их в окно нашего приложения. Для каждого элемента панели вкладок мы добавляем на эту панель навигационный контроллер или контроллер вида. Эти элементы будут отображаться как вкладки на панели. Контроллер панели вкладок содержит панель вкладок типа UITabBar. Мы не создаем этот объект вручную – мы создаем контроллер панели вкладок, а уже он создает для нас такой объект. Проще говоря, считайте, что мы инстанцируем контроллер панели вкладок, а потом задаем контроллеры видов для этой панели. Данные контроллеры видов будут относиться к типу UIViewController или UINavigationController, если мы собираемся создать по контроллеру для каждого элемента панели вкладки (они же – контроллеры видов, задаваемые для контроллера панели вкладок). Навигационные контроллеры относятся к типу UINavigationController и являются подклассами от UIViewController. Следовательно, навигационный контроллер – это контроллер вида, но контроллеры видов, относящиеся к типу UIViewController, не являются навигационными контроллерами.

Итак, предположим, что у нас есть два контроллера видов. Классы этих контроллеров называются FirstViewController и SecondViewController:


– (BOOL) application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{


self.window = [[UIWindow alloc] initWithFrame:

[[UIScreen mainScreen] bounds]];


[self.window makeKeyAndVisible];


FirstViewController *firstViewController = [[FirstViewController alloc]

initWithNibName: nil

bundle: NULL];


SecondViewController *secondViewController = [[SecondViewController alloc]

initWithNibName: nil

bundle: NULL];


UITabBarController *tabBarController = [[UITabBarController alloc] init];

[tabBarController setViewControllers:@[firstViewController,

secondViewController

]];


self.window.rootViewController = tabBarController;


return YES;

}


Когда панель вкладок отобразится на экране, ее элементы будут расположены именно так, как показано на рис. 1.38. Имя каждого из этих элементов основывается на названии того контроллера вида, который соответствует конкретному элементу. Определим заголовки для обоих контроллеров наших видов.

Когда загружается панель вкладок, вместе с ней загружается контроллер вида первого входящего в нее элемента. Все остальные контроллеры видов инициализируются, но их виды не загружаются. Это означает, что любой код, который вы напишете во viewDidLoad второго контроллера вида, не выполнится до тех пор, пока пользователь не нажмет второй элемент этой панели в первый раз. Поэтому если вы присвоите заголовок панели контроллеру второго вида в его viewDidLoad и запустите приложение, то обнаружите, что заголовок панели вкладок по-прежнему пуст.

Первый контроллер вида мы назовем First:

#import "FirstViewController.h"


@implementation FirstViewController


– (id)initWithNibName:(NSString *)nibNameOrNil

bundle:(NSBundle *)nibBundleOrNil{


self = [super initWithNibName: nibNameOrNil

bundle: nibBundleOrNil];

if (self!= nil) {

self.title = @"First";

}

return self;


}


– (void)viewDidLoad{

[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

}


А второй контроллер вида будет называться Second:


#import "SecondViewController.h"


@implementation SecondViewController


– (id)initWithNibName:(NSString *)nibNameOrNil

bundle:(NSBundle *)nibBundleOrNil{


self = [super initWithNibName: nibNameOrNil

bundle: nibBundleOrNil];

if (self!= nil) {

self.title = @"Second";

}

return self;


}


– (void)viewDidLoad{

[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];


}


Теперь запустим приложение и посмотрим, что получилось (рис. 1.42).


Рис. 1.42. Очень простая панель вкладок, на которой находятся два контроллера вида


Как видите, у контроллеров видов нет навигационной панели. Что делать? Все просто. Как вы помните, UINavigationController – это подкласс UIViewController. Итак, мы можем добавлять экземпляры навигационных контроллеров на панель вкладок, а внутрь каждого навигационного контроллера загрузить контроллер вида. Чего же мы ждем?


– (BOOL) application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{


// Точка переопределения для специальной настройки,

// выполняемой после запуска приложения.

self.window = [[UIWindow alloc] initWithFrame:

[[UIScreen mainScreen] bounds]];


[self.window makeKeyAndVisible];


FirstViewController *firstViewController = [[FirstViewController alloc]

initWithNibName: nil

bundle: NULL];


UINavigationController *firstNavigationController =

[[UINavigationController alloc]

initWithRootViewController: firstViewController];


SecondViewController *secondViewController = [[SecondViewController alloc]

initWithNibName: nil

bundle: NULL];


UINavigationController *secondNavigationController =

[[UINavigationController alloc]

initWithRootViewController: secondViewController];


UITabBarController *tabBarController = [[UITabBarController alloc] init];


[tabBarController setViewControllers:

@[firstNavigationController, secondNavigationController]];


self.window.rootViewController = tabBarController;


return YES;


}


Что получается? Именно то, что мы хотели (рис. 1.43).


Рис. 1.43. Панель вкладок, на которой контроллеры видов находятся внутри навигационных контроллеров


Как было показано на рис. 1.38, каждый элемент панели вкладок может содержать текст или изображение. Мы узнали, что, пользуясь свойством title контроллера вида, можно задавать такой текст. А что насчет изображения? Оказывается, у каждого контроллера вида есть и свойство tabItem. Это свойство соответствует той вкладке, которая находится в актуальном контроллере вида. Вы можете пользоваться этим свойством, чтобы задавать изображение для вкладки. Изображение для вкладки задается через ее свойство image. Я уже сделал два изображения – прямоугольник и кружок, а теперь выведу их как изображения для вкладок, соответствующих каждому из моих контроллеров видов. Вот код для первого контроллера вида:


– (id)initWithNibName:(NSString *)nibNameOrNil

bundle:(NSBundle *)nibBundleOrNil{


self = [super initWithNibName: nibNameOrNil

bundle: nibBundleOrNil];

if (self!= nil) {

self.title = @"First";

self.tabBarItem.image = [UIImage imageNamed:@"FirstTab"];

}

return self;


}

– (void)viewDidLoad{

[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

}

А вот код для второго контроллера:

– (id)initWithNibName:(NSString *)nibNameOrNil

bundle:(NSBundle *)nibBundleOrNil{


self = [super initWithNibName: nibNameOrNil

bundle: nibBundleOrNil];

if (self!= nil) {

self.title = @"Second";

self.tabBarItem.image = [UIImage imageNamed:@"SecondTab"];

}

return self;


}


– (void)viewDidLoad{

[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

}


Запустив приложение в эмуляторе, увидим такую картинку, как на рис. 1.44.


Рис. 1.44. Элементы панели вкладок с изображениями

1.17. Отображение статического текста с помощью UILabel

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

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

Статическим называется такой текст, который пользователь не может напрямую изменять во время исполнения.

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

Используйте класс UILabel.

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

Подписи (Labels) встречаются в iOS повсюду. Они используются практически в любых приложениях, за исключением игр, для отображения содержимого которых обычно применяется OpenGL ES, а не основные фреймворки отрисовки, входящие в состав iOS. На рис. 1.45 показаны несколько подписей, имеющихся в приложении Settings (Настройки) для iPhone.


Рис. 1.45. Подписи в качестве названий настроек


Как видите, подписи содержат текстовые названия разделов приложения Settings (Настройки), в частности iCloud, Twitter, FaceTime, Safari и т. д.

Чтобы создать подпись, необходимо инстанцировать объект типа UILabel. Установка или получение текста для подписи осуществляется с помощью свойства text. Итак, определим подпись в файле реализации контроллера нашего вида:


#import "ViewController.h"


@interface ViewController ()

@property (nonatomic, strong) UILabel *myLabel;

@end


@implementation ViewController


А теперь в viewDidLoad инстанцируем подпись и сообщаем среде времени исполнения, где следует разместить подпись (эта информация указывается в свойстве frame) и в какой вид она должна быть добавлена. В данном случае подпись окажется в виде контроллера нашего вида:


– (void)viewDidLoad{

[super viewDidLoad];


CGRect labelFrame = CGRectMake(0.0f,

0.0f,

100.0f,

23.0f);

self.myLabel = [[UILabel alloc] initWithFrame: labelFrame];

self.myLabel.text = @"iOS 7 Programming Cookbook";

self.myLabel.font = [UIFont boldSystemFontOfSize:14.0f];

self.myLabel.center = self.view.center;

[self.view addSubview: self.myLabel];


}


Теперь запустим приложение и посмотрим, что происходит (рис. 1.46).


Рис. 1.46. Слишком длинная подпись, которая не умещается на экране


Как видите, текст (содержимое) подписи обрезается, а за ним идут точки, поскольку ширины поля для подписи недостаточно для того, чтобы уместился весь текст. Для решения этой проблемы можно было бы увеличить ширину, но что делать с высотой? А что, если мы хотим, чтобы текст переходил на следующую строку. Хорошо, увеличим высоту с 23.0f до 50.0f:


CGRect labelFrame = CGRectMake(0.0f,

0.0f,

100.0f,

50.0f);


Если сейчас запустить приложение, получится тот же самый результат, что и на рис. 1.46. Вы могли бы спросить: «Я увеличил высоту, так почему же текст не переходит на следующую строку»? Оказывается, у класса UILabel есть свойство numberOfLines, в котором нужно указать, на сколько строк должен разбиваться текст подписи, если в ширину для нее будет недостаточно места. Если задать здесь значение 3, то вы сообщите программе, что текст подписи должен занимать не более трех строк, если этот текст не умещается в одной строке:


– (void)viewDidLoad{

[super viewDidLoad];


CGRect labelFrame = CGRectMake(0.0f,

0.0f,

100.0f,

70.0f);

self.myLabel = [[UILabel alloc] initWithFrame: labelFrame];

self.myLabel.numberOfLines = 3;

self.myLabel.lineBreakMode = NSLineBreakByWordWrapping;

self.myLabel.text = @"iOS 7 Programming Cookbook";

self.myLabel.font = [UIFont boldSystemFontOfSize:14.0f];

self.myLabel.center = self.view.center;

[self.view addSubview: self.myLabel];


}


Теперь при запуске программы вы получите желаемый результат (рис. 1.47).


Рис. 1.47. Подпись, текст которой занимает три строки

Бывает, что вы не знаете, сколько строк понадобится, чтобы отобразить текст подписи. В таких случаях для свойства numberOfLines подписи задается значение 0.

Если вы хотите, чтобы рамка, в которой находится подпись, имела постоянные размеры, а размер шрифта корректировался так, чтобы он входил в отведенные границы, необходимо задать для свойства adjustsFontSizeToFitWidth подписи значение YES. Например, если высота подписи равна 23.0f, как показано на рис. 1.46, то можно уместить шрифт подписи в этих границах. Вот как это делается:


– (void)viewDidLoad{

[super viewDidLoad];


self.view.backgroundColor = [UIColor whiteColor];

CGRect labelFrame = CGRectMake(0.0f,

0.0f,

100.0f,

23.0f);

self.myLabel = [[UILabel alloc] initWithFrame: labelFrame];

self.myLabel.adjustsFontSizeToFitWidth = YES;

self.myLabel.text = @"iOS 7 Programming Cookbook";

self.myLabel.font = [UIFont boldSystemFontOfSize:14.0f];

self.myLabel.center = self.view.center;

[self.view addSubview: self.myLabel];


}

1.18. Оформление UILabel

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

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

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

Пользуйтесь перечисленными далее свойствами класса UILabel в зависимости от стоящей перед вами задачи.

• shadowColor – свойство типа UIColor. Как понятно из названия, оно указывает цвет отбрасываемой тени для подписи. Устанавливая это свойство, вы должны установить и свойство shadowOffset.

• shadowOffset – это свойство типа CGSize. Оно указывает размер отступа между тенью и текстом. Например, если вы зададите для этого свойства значение (1, 0), то тень будет находиться на одну точку правее текста. Если задать значение (1, 2), то тень окажется на одну правее и на одну точку ниже текста. Если же установить значение (-2, -10), то тень будет отображаться на две точки левее и на десять точек выше текста.

• numberOfLines – свойство представляет собой целое число, указывающее, сколько строк текста может включать в себя подпись.


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