Pull to refresh

Авторотация сложных интерфейсов в программах для iPad

Reading time5 min
Views4.5K
Большая часть программ для 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:

#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.


Вот мы и получили плавную анимацию изменения сложного интерфейса при смене ориентации. Минимум кода и ничего сложного.
Tags:
Hubs:
+28
Comments18

Articles