Как правильно проектировать iPad с несколькими ориентациями

Каков правильный способ разработки iPad-приложения с несколькими ориентациями в настоящее время? Я прочитал много документов Apple, веб-ресурсов и некоторых SO Q & A. Вот мои первоначальные требования:

  • Это должно работать на iOS 5 и выше. Нет необходимости создавать совместимость с предыдущими версиями iOS.
  • Я хотел бы, если возможно, иметь портретный и ландшафтный пользовательский интерфейс, определенные в разных файлах NIB.
  • Мои файлы NIB будут иметь разные изображения для одинаковых элементов интерфейса в другой ориентации (например, у меня будут header.png и header-landscape.png UIImageView.
  • В приложении будет несколько экранов, и мне нужно будет сменить ориентацию на каждом из них.

Так что мне делать?

  • Создайте один VC на экран и замените основной вид в обработчике willRotate?
  • Создайте один VC для каждой ориентации? Но тогда как вы их правильно переключаете?
  • Просто повторная компоновка элементов не будет работать (я думаю), потому что мне придется перезагружать изображения.
  • Пишите все в код (я бы действительно ненавидел эту идею)?

Каковы правильные подходы к этому вопросу на сегодняшний день?

Ответы

Ответ 1

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

Ради того, чтобы не сбрасывать все остальные ответы на этой странице, Я опубликовал полную запись в своем блоге и ссылка на некоторый пример кода

Резюме

Предпочтительно, чтобы ваш пользовательский интерфейс отображался в .xib файлах, хотя степень, от которой вы позволяете себе расходиться, частично зависит от набора навыков людей, которые изменят ваше приложение в будущем. Это могут быть не просто программисты!

Предпочтительный вариант

Следует строго придерживаться одного логического представления с одним .xib файлом и одним подклассом UIViewController. Постарайтесь сделать это очень сложно. Установка autoresizesSubviews=YES на ваш корневой каталог XIB view, и правильная настройка дочерних представлений 'autoresizingMask для гибки с изменениями размера/ориентации экрана может пройти долгий путь.

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

Вариант 1

Если макет для портрета или пейзажа не слишком отличается, то я рекомендую оставаться с одним .xib и иметь немного кода в вашем контроллере просмотра для настройки макета при вращении.

Вариант второй

Если различия между пейзажем и портретом действительно значительны, я рекомендую иметь один .xib для каждой ориентации (со строгим соглашением об именах, например MyViewController.xib и MyViewController-landscape.xib). Но оба файла .xib должны подключить File Owner к тому же классу View Controller! Для меня это ключевое слово.

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


Решение

Я создал такой базовый класс, и поместил его в примерный проект здесь. Вы можете увидеть пример Hello World, как я думаю, все необходимо обработать три сценария:

  • Один контроллер вида и один .xib, только с авторезистированием (my FirstViewController)
  • Один контроллер вида и два .xibs, с автоматическим переключением между ними (my SecondViewController)
  • Один контроллер вида и один .xib, с малой программной компоновкой при поворотах (ThirdViewController)

RotatingViewController базовый класс, который я использую, одинаково применим к приложениям iPhone. На самом деле у меня есть более сложная версия, которая обрабатывает ландшафтные макеты iPad и iPhone, портрет и (для универсальных приложений).

Но этот вопрос касался только iPad, поэтому я раздели его, чтобы было легче понять.

Мой базовый класс также имеет метод утилиты imageNamed:, который помогает загружать изображения, подходящие для текущей ориентации (с именем image-landscape.png). Тем не менее, я думаю, что растягиваемые UIImages следует использовать в подавляющем большинстве случаев.

Я этого не делал, но RotatingViewController мог также попытаться пройти его дерево subviews и обновить свойство image на объектах UIButton или UIImageView, когда меняется ориентация устройства. Я не дошел до такой длины, но вы могли.

Более обоснование для этих рекомендаций доступно в сообщении в блоге. Я ссылаюсь на

Ответ 2

Итак, с отсутствием ответов на этот вопрос и время - проблема, я закончил делать следующее:

  • Используемый интерфейс Builder для создания файлов NIB для всех экранов в портретной ориентации. Связывает все элементы управления, для которых требуется макет.
  • Используемый IB для создания файлов NIB для ландшафтной ориентации также, но использовал его только для ссылки, чтобы увидеть, какие рамки для элементов пользовательского интерфейса будут в ландшафте.
  • Добавлен код, чтобы переустановить все элементы в альбомную ориентацию и вернуться к портрету в обработчике willAutoRotate.

Этот метод дал мне возможность создавать в большинстве списков пользовательского интерфейса в IB. Мне все еще нужно сохранить код, чтобы перегруппировать элементы в разные ориентации, но обычно это включает в себя методы setFrame для меток, кнопок и т.д. И imageNamed для изображений. Это намного меньше, чем при создании всего пользовательского интерфейса в коде.

Я открою щедрость по этому вопросу, как только SO позволит, потому что я думаю, что этот вопрос очень важен и полезен для любого разработчика, создающего универсальное и многооконное приложение для iPad/iPhone.

Ответ 3

Я использовал 3 разных метода, 1 из которых, я думаю, является "правильным" способом обработки нескольких ориентаций.

  • Неправильно: создаются два разных nib/xib. Не "плохо", но больно обрабатывать контекст и состояние, когда вы постоянно восстанавливаете UIView в UIViewController.
  • Неправильно: использовал один наконечник и переместил их во вращение на основе абсолютных координат. Это неправильный способ сделать это. Я видел это снова и снова, но это худший способ справиться с несколькими режимами просмотра. Симптомом этого являются UIViews, которые ориентированы на устройство. Полностью ненужный.
  • Правильно. Используйте метод autoresizingMask для элементов внутри представления, чтобы поместить их в правильное положение при вращении устройства, чтобы настроить то, что не может быть выполнено с использованием кадра CGRect. Мне нужно было сделать это только один раз, чтобы выровнять что-то. IMHO это "правильный" способ обработки нескольких ориентаций устройств. UIView и любые подзаголовки не должны знать о вращении. Вы можете использовать один VC для каждого экрана с большим количеством подзапросов и поддерживать его просто. Если ваш макет может быть разработан таким образом, с плавающими элементами, тогда вы будете золотыми, а пользовательский интерфейс - легкий ветерок.

Просто мои два цента.

Изменить: iOS 6 представил AutoLayout и может использоваться вместо "распорок и пружин" - https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/Introduction/Introduction.html

Ответ 4

Мне неудивительно, что Apple не предоставляет способ использования нескольких XIB файлов (по одному для каждой ориентации) для данного контроллера представлений - это будет отличный способ справиться с проблемами ориентации, поскольку авторезистировка редко обрабатывает ориентацию (он работает только с очень простыми интерфейсами).

Вы можете сделать это вместо этого: создать XIB для портрета и присвоить каждому подвью в XIB уникальное свойство тега. Затем дублируйте XIB и заново создайте макет для пейзажа (теперь у вас есть два XIB, один портрет и один альбом).

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

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

В layoutSubviews (фактически в viewDidLayoutSubviews, поскольку вы имеете дело с контроллерами представлений, и вы можете сделать iOS 5+), все, что вам нужно сделать, - это рекурсивно перебирать все подсайты и назначать каждому подвью кадр из словаря кадров, подходящих для текущей ориентации, на основе свойства тега subview.

Этот метод позволит вам сохранить состояние вашего контроллера вида, не перезагружая его заново при каждом изменении ориентации. Это также позволяет вам выстраивать контроллеры своего вида с помощью IB, поэтому вам не нужно писать кучу кода макета макета.

Ответ 5

Зачем запускать приложение, которое может делать все? Когда вы разрабатываете приложение, вы решаете, какая именно ориентация для него - пейзаж или портрет - и даже если вашему дизайну приложения потребуется обратная ориентация (все в ландшафтном и 1-2 контроллера - портрет или наоборот), вы сделают перья соответственно. Ну, в некоторых случаях вам понадобится контроллер для поддержки всех ориентаций, и вы это сделаете.

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

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