Большая часть программ для iPhone и iPod touch поддерживают только портретную ориентацию. Многие разработчики даже не задумывались о том, чтобы добавить ландшафтную (альбомную) ориентацию там, где она действительно нужна. Не исключение и компания Apple, которая в iPhone OS 2.x подавала не самые лучшие примеры, не реализовывая поддержку ландшафтной (альбомной) ориентации в важных системных программах (в iPhone OS 3.x компания исправила свою ошибку).
С приходом iPad ситуация изменилась. Компания Apple обязала всех разработчиков поддерживать все ориентации устройства в программах для iPad. Естественно, могут быть исключения, например, игры. Но программы, которые не имеют жёсткой привязки (функциональной) к ориентации, должны быть дружелюбны к пользователю в любом положении устройства.
С простыми интерфейсами сложностей никаких нет. Объектам класса UIView задаётся необходимое свойство autoresizingMask, которое описывает изменение фрейма. К сложным интерфейсами такой метод уже не подходит.
Я расскажу, как сделать плавную и приятную авторотацию интерфейса программы с помощью метода layoutSubviews. Получить детальную информацию об этом методе можно в iPad Programming Guide. Я лишь приведу реальный практически пример его использования (документация от Apple скупа в этом плане).
Это один из вариантов, но результат его работы очень качественный. Естественно, этот вариант подходит для iPad и iPhone / iPod touch.
Допустим, мы хотим иметь следующие портретный и ландшафтный (альбомный) виды:


Сразу выкладываю финальный проект RotateDemo.
И видео:
Создадим базовый проект для iPad (Window-based).
Я привык весь интерфейс делать программно. Если вы хотите, то легко можете заменить часть кода на щёлканье мышкой в Interface Builder.
Добавим в проект файлы класса ContainerView (производный от UIView). Оставим пока его пустым. Объект этого класса будет контейнером всех объектов UIView в нашем контроллере. Именно в этом класса мы переназначим метод layoutSubviews.
Создадим файлы класса DemoViewController (производный от UIViewController).
Наш интерфейсный файл DemoViewController.h:
В реализации класса нам важен только один основной метод loadView:
Здесь всё просто. Мы создаём контейнер и добавляем в него все наши элементы. В примере это просто 4 кнопки UIButton. Фреймы кнопок не имеют никакого значения (они будут установлены в методе layoutSubviews).
Возвращаемся к нашему классу ContainerView и переопределяем метод layoutSubviews:
В примере используется сравнение с абсолютной шириной. Как вариант, можно использовать универсальную проверку:
Готово. Осталось только активизировать наш контроллер в классе делегата:
Вот мы и получили плавную анимацию изменения сложного интерфейса при смене ориентации. Минимум кода и ничего сложного.
С приходом iPad ситуация изменилась. Компания Apple обязала всех разработчиков поддерживать все ориентации устройства в программах для iPad. Естественно, могут быть исключения, например, игры. Но программы, которые не имеют жёсткой привязки (функциональной) к ориентации, должны быть дружелюбны к пользователю в любом положении устройства.
С простыми интерфейсами сложностей никаких нет. Объектам класса UIView задаётся необходимое свойство autoresizingMask, которое описывает изменение фрейма. К сложным интерфейсами такой метод уже не подходит.
Я расскажу, как сделать плавную и приятную авторотацию интерфейса программы с помощью метода layoutSubviews. Получить детальную информацию об этом методе можно в iPad Programming Guide. Я лишь приведу реальный практически пример его использования (документация от Apple скупа в этом плане).
Это один из вариантов, но результат его работы очень качественный. Естественно, этот вариант подходит для iPad и iPhone / iPod touch.
Допустим, мы хотим иметь следующие портретный и ландшафтный (альбомный) виды:


Сразу выкладываю финальный проект RotateDemo.
И видео:
Создадим базовый проект для iPad (Window-based).
Я привык весь интерфейс делать программно. Если вы хотите, то легко можете заменить часть кода на щёлканье мышкой в Interface Builder.
Добавим в проект файлы класса ContainerView (производный от UIView). Оставим пока его пустым. Объект этого класса будет контейнером всех объектов UIView в нашем контроллере. Именно в этом класса мы переназначим метод layoutSubviews.
Создадим файлы класса DemoViewController (производный от UIViewController).
Наш интерфейсный файл DemoViewController.h:
#import <UIKit/UIKit.h>
#import "ContainerView.h"
@interface DemoViewController : UIViewController
{
ContainerView *containerView;
}
@end
* This source code was highlighted with Source Code Highlighter.
В реализации класса нам важен только один основной метод loadView:
- (void)loadView
{
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:screenRect];
contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
contentView.backgroundColor = [UIColor blueColor];
self.view = contentView;
[contentView release];
containerView = [[ContainerView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
containerView.backgroundColor = [UIColor blueColor];
containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:containerView];
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1.frame = CGRectZero;
[button1 setTitle:@"Object 1" forState:UIControlStateNormal];
button1.tag = 1001;
[containerView addSubview:button1];
UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button2.frame = CGRectZero;
[button2 setTitle:@"Object 2" forState:UIControlStateNormal];
button2.tag = 1002;
[containerView addSubview:button2];
UIButton *button3 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button3.frame = CGRectZero;
[button3 setTitle:@"Object 3" forState:UIControlStateNormal];
button3.tag = 1003;
[containerView addSubview:button3];
UIButton *button4 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button4.frame = CGRectZero;
[button4 setTitle:@"Object 4" forState:UIControlStateNormal];
button4.tag = 1004;
[containerView addSubview:button4];
}
* This source code was highlighted with Source Code Highlighter.
Здесь всё просто. Мы создаём контейнер и добавляем в него все наши элементы. В примере это просто 4 кнопки UIButton. Фреймы кнопок не имеют никакого значения (они будут установлены в методе layoutSubviews).
Возвращаемся к нашему классу ContainerView и переопределяем метод layoutSubviews:
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.frame.size.width == 768)
{
UIView *view = [self viewWithTag:1001];
view.frame = CGRectMake(184, 100, 400, 150);
view = [self viewWithTag:1002];
view.frame = CGRectMake(184, 300, 400, 150);
view = [self viewWithTag:1003];
view.frame = CGRectMake(184, 500, 400, 150);
view = [self viewWithTag:1004];
view.frame = CGRectMake(184, 700, 400, 150);
}
else
{
UIView *view = [self viewWithTag:1001];
view.frame = CGRectMake(74, 100, 400, 150);
view = [self viewWithTag:1002];
view.frame = CGRectMake(550, 100, 400, 150);
view = [self viewWithTag:1003];
view.frame = CGRectMake(74, 400, 400, 150);
view = [self viewWithTag:1004];
view.frame = CGRectMake(550, 400, 400, 150);
}
}
* This source code was highlighted with Source Code Highlighter.
В примере используется сравнение с абсолютной шириной. Как вариант, можно использовать универсальную проверку:
if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]))
* This source code was highlighted with Source Code Highlighter.
Готово. Осталось только активизировать наш контроллер в классе делегата:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
controller = [[DemoViewController alloc] initWithNibName:nil bundle:nil];
window.backgroundColor = [UIColor blueColor];
[window addSubview:controller.view];
[window makeKeyAndVisible];
return YES;
}
* This source code was highlighted with Source Code Highlighter.
Вот мы и получили плавную анимацию изменения сложного интерфейса при смене ориентации. Минимум кода и ничего сложного.