ПРОГРАММИРОВАНИЕ ПОД IPHONE, IPAD OBJECTIVE-C часть 2

13. Простые примеры работы с интерфейсом

Универсальное приложение (Universal App)

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

Для начала создадим обычный проект только для iPhone. Прект будет на основе шаблона Master-Detail Application и назовем его UniversalApp.

Добавим в проект картинку, которую можно скачать по этой ссылке. Эта картинка имеет размер 200×120 пикселей. Добавим в файл DetailViewController.xib объект типа UIImageView таких же размеров и укажем ему эту картинку. Ничего особенного мы не сделали. Если запустить приложение на симуляторе — мы увидим обычную картинку. Но самое интересное заничается, когда это приложение установить на реальное устройство с Retina дисплеем. В этом случае мы получим размытое зернистое изображение.

Происходит это потому, что у Retina дисплея размер пикселя в два раза меньше обычного, а значит, ему нужно «скармливать» в два раза больше картинки. Картинки больше у нас нету, поэтому мы уменьшим размер UIImageView. Если теперь запустить приложение на устройстве — все будет отлично отображаться. Но на симуляторе или на устройстве без Retina дисплея мы снова получим не качественное изображение. Это связано с тем, что iOS не умеет не только увеличивать, но и уменьшать графические файлы.

Для достижения «золотой» середины, следует добавить в проект два файла. Уменьшим в два раза уже добавленный файл, а так же скачаем новый (по той же ссылке), дадим ему имя logo@2x.png и добавим в проект. При этом, размер нового файла и UIImageViewизменять не будем. И имя файла изображения, которое указывали UIImageView изменять тоже не будем (за нас это сделает iOS). Теперь наше приложение будет корректно отображаться на любом iPhone. То есть, оперировать нам следует только с именами без окончания @2x. Если вы хототите указать изображение в конструкторе интерфейса, делать это следует так:

Если вы хотите в коде указать изображение какому-то объекту — так же следует использовать имя файла без приставки:

<code data-result="[object Object]">UIImage *logoImage = [UIImage imageNamed:@"logo.png"];</code>

iOS сама определит тип экрана и подставит нужное изображение (с приствавкой @2x), если оно будет в проекте.

С телефонами разобрались, теперь перейдем к iPad. Если мы в списке устройств, на которые хотим скомпилировать приложение выберем iPad:

То получим вот такую картинку:

Такой же результат будет при установке пользователем приложения купленного в AppStore на iPad. То есть, iPad поддерживает приложения для iPhone, т.к. пишуться они на одном языке программирования разница лишь в интерфейсе. То есть, для исправления ситуации нам нужно всего лишь добавить файлы интерфейса для iPad (и указать в Xcode, что наше приложение универсальное).

Выберем в инспекторе файлов наш проект, затем его же в списке таргетов и там на вкладке Summary изменим значение поля Devices сiPhone на Universal.

Если сейчас запустить приложение — оно уже будет нормально работать на iPad. Произойдет это потому, что все файлы интерфейсов проекта будут растянуты до размеров экрана  iPad, но это не означает, что сделано это будет всегда корректно. Поэтому, как я уже говорил, предлагаю добавить еще один файл интерфейса в проект. Для этого нажмем правой кнопкой на папке UniversalApp в инспекторе файлов и с выпадающего меню выберем пункт New File….

Перед нами откроется знакомое окно создания нового файла. В левой части этого окна выберем пункт User Interface, а в правой — Empty.

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

Мы выбераем тип iPad и снова нажимаем на кнопку Next. После чего последует знакомое окно завершения создания нового файла. В поле Save As: укажем имя DetailViewController-iPad и нажмем кнопку Create.

После чего в проект будет добавлен новый файл:

Но это файл пустой (это и не удевительно, мы же выбралти тип Empty). В первую очередь добавим в него UIView. Просто выберите этот объект с библиотеки объектов и перетяните на свободную область.

Нашему UIView автоматически назначится размер iPad. Теперь следует указать к какому классу относиться наш файл интерфейса. Для этого в списке Placeholders выберите объект File’s Owner, затем в меню утелитов выберите раздел Identity inspector и в поле Classукажите DetailViewController (имя класа может подсвечиваться при вводе первых трех букв, но не всегда, если это не произошло — пишите имя полностью самостоятельно).

 

После этого можно связать объект view с нашим интерфейсом.

 

 

Теперь на наш интерфейс можно добавлять любые объекты и они будут отображаться на iPad так, как в xib-файле. Давайте проделаем с ним ту же операцию, что в самом начале с DetailViewController.xib. То есть, добавим на него объект UIImageView (с размером 200×120 пикселей). Затем снова скачаем логотип нашего сайта (ссылка), но теперь дадим ему имя logo-iPad.png и добавим его в проект. Укажем UIImageView (в DetailViewController-iPad.xib) только что добавленную картинку.

 

Здесь следует обратить внимание на тот факт, что содержимое файлов logo@2x.png и logo-iPad.png. По сути, это один и тот же файл, только с разными именами. Можно было бы UIImageView для iPad указать имя первого файла и не заморачиваться со вторым. Но я не знаю как поведет себя приложение с выходом iPad с Retina дисплеем, а слухи о его выходе все больше наполняют Интернет…

 

Теперь осталось правильно вызывать наш файл интерфейса. В первую очередь нам нужно будет програмно определять на каком устройстве запущено приложение. Поскольку обычно это делать прихоится часто — я создал два дэфайна и добавил их в MasterViewController.h:

 

<code data-result="[object Object]">#define isiPad UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad
#define prefixDevice isiPad?@"-iPad":@""</code>

 

Подробнее о дефайнах я писал здесь. Попробуем использовать первый дэфайн. Добавим в файл MasterViewController.m метод, который устанавливает высоту ячейки таблици:

 

<code data-result="[object Object]">- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    return isiPad?60.0f:44.0f;
}</code>

 

Теперь высота ячейки будет устанавливаться в зависимости от устройства. Подобный образом внесем изменения в метод didSelectRowAtIndexPath. Вот так он выглядел:

 

<code data-result="[object Object]">- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (!self.detailViewController) {
        self.detailViewController = [[[DetailViewController alloc] 
                                      initWithNibName:@"DetailViewController" 
                                      bundle:nil] autorelease];
    }
    [self.navigationController pushViewController:self.detailViewController animated:YES];
}</code>

 

А вот так, после наших поправок:

 

<code data-result="[object Object]">- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (!self.detailViewController) {
        NSString *nibName = [NSString stringWithFormat:@"DetailViewController%@", prefixDevice];

        self.detailViewController = [[[DetailViewController alloc] 
                                      initWithNibName:nibName
                                      bundle:nil] autorelease];
    }
    [self.navigationController pushViewController:self.detailViewController animated:YES];
}</code>

 

Вот и все, наше приложение стало универсальным и корректно отображается на всех устройствах.

 

На последок хотелось бы сделать замечание по поводу одного метода. Этот метод есть в шпоргалке, он возвращает фрэйм экрана:

 

<code data-result="[object Object]">CGRect screenRect = [[UIScreen mainScreen] applicationFrame];</code>

 

Я видел индусский код, в котором для определения типа устройства использовался именно этот мтеод. И здесь следует обратить внимание на один важный момент, устройство с Retina дисплеем имеет такой же фрэйм как без него. То есть, количество пикселей — больше, но соотношение сторон — такое же.

 

Исходный код этого проекта можно скачать здесь.