Я в основном хочу, чтобы мои подвиды располагались по-разному в зависимости от ориентации iPad (книжная или альбомная) с использованием классов размеров, представленных в xcode 6. Я нашел множество руководств, объясняющих, как разные классы размеров доступны для Iphone в портретной и альбомной ориентации на IB. но, тем не менее, похоже, что нет ни одного, охватывающего отдельные ландшафтные или портретные режимы для iPad на IB. Кто-нибудь может помочь?
objective-c
ios8
size-classes
adaptive-ui
neelIVP
источник
источник
Ответы:
Похоже, что Apple намерена рассматривать обе ориентации iPad как одну и ту же, но, как некоторые из нас находят, есть вполне законные причины дизайна, чтобы захотеть изменить макет пользовательского интерфейса для iPad Portrait и iPad Landscape.
К сожалению, текущая ОС, похоже, не поддерживает это различие ... это означает, что мы вернулись к манипулированию ограничениями автоматической компоновки в коде или аналогичными обходными путями для достижения того, что мы в идеале должны иметь возможность получить бесплатно с помощью адаптивного пользовательского интерфейса. .
Не изящное решение.
Разве нет способа использовать магию, которую Apple уже встроила в IB и UIKit, чтобы использовать размерный класс по нашему выбору для данной ориентации?
~
Обдумывая проблему в более общем плане, я понял, что «классы размера» - это просто способы обратиться к нескольким макетам, хранящимся в IB, чтобы их можно было вызывать по мере необходимости во время выполнения.
Фактически, «размерный класс» - это просто пара значений перечисления. Из UIInterface.h:
Итак, независимо от того, как Apple решила назвать эти разные варианты, по сути, это просто пара целых чисел, используемых в качестве своего рода уникального идентификатора, чтобы отличить один макет от другого, хранящегося в IB.
Теперь предположим, что мы создаем альтернативный макет (с использованием неиспользуемого класса размера) в IB - скажем, для iPad Portrait ... есть ли способ заставить устройство использовать наш выбор класса размера (макет пользовательского интерфейса) по мере необходимости во время выполнения ?
Попробовав несколько различных (менее элегантных) подходов к проблеме, я подозревал, что есть способ программно переопределить класс размера по умолчанию. И есть (в UIViewController.h):
Таким образом, если вы можете упаковать иерархию контроллера представления как «дочерний» контроллер представления и добавить его к родительскому контроллеру представления верхнего уровня ... тогда вы можете условно переопределить дочерний элемент, думая, что это класс другого размера, чем класс по умолчанию из ОС.
Вот пример реализации, которая делает это в «родительском» контроллере представления:
В качестве быстрой демонстрации, чтобы увидеть, работает ли это, я добавил настраиваемые метки специально для версий 'Regular / Regular' и 'Compact / Regular' макета дочернего контроллера в IB:
А вот как это выглядит, когда iPad находится в обеих ориентациях:
Вуаля! Конфигурации классов нестандартного размера во время выполнения.
Надеюсь, Apple сделает это ненужным в следующей версии ОС. Между тем, это может быть более элегантный и масштабируемый подход, чем программная возня с ограничениями автоматической компоновки или выполнение других манипуляций в коде.
~
РЕДАКТИРОВАТЬ (6/4/15): имейте в виду, что приведенный выше образец кода по сути является доказательством концепции для демонстрации техники. Не стесняйтесь при необходимости адаптироваться к вашему конкретному приложению.
~
РЕДАКТИРОВАТЬ (7/24/15): отрадно, что приведенное выше объяснение, похоже, помогает прояснить проблему. Хотя я не тестировал его, код mohamede1945 [ниже] выглядит как полезная оптимизация для практических целей. Не стесняйтесь протестировать его и сообщить нам, что вы думаете. (Для полноты картины я оставлю приведенный выше пример кода как есть.)
источник
UITraitCollection
достаточно оптимизирован иoverrideTraitCollectionForChildViewController
вызывается достаточно редко, поэтому выполнить проверку ширины и затем создать ее не должно быть проблемой.Подводя итог очень длинному ответу Рона Даймонда. Все, что вам нужно сделать, это в вашем корневом контроллере представления.
Objective-c
Swift:
Затем в Storyborad используйте компактную ширину для портрета и обычную ширину для ландшафта.
источник
- (UITraitCollection *)traitCollection
вместоoverrideTraitCollectionForChildViewController
. Также ограничения должны соответствовать коллекциям признаков, поэтому wC (hAny).IPad имеет «обычный» размер как по горизонтали, так и по вертикали, не делая различий между портретом и пейзажем.
Эти характеристики размера можно переопределить в пользовательском
UIViewController
коде подкласса с помощью методаtraitCollection
, например:Это дает iPad такие же габариты, как и iPhone 7 Plus. Обратите внимание, что другие модели iPhone обычно имеют свойство «компактной ширины» (а не обычной ширины) независимо от ориентации.
Подобная имитация iPhone 7 Plus позволяет использовать эту модель в качестве замены iPad в Interface Builder Xcode, который не знает о настройках в коде.
Имейте в виду, что режим Split View на iPad может отличаться по размеру от обычного полноэкранного режима.
Этот ответ основан на подходе, принятом в этом сообщении в блоге , с некоторыми улучшениями.
Обновление 2019-01-02: Обновлено, чтобы исправить периодически возникающую скрытую строку состояния в ландшафте iPad и потенциальное попирание (новых) черт в
UITraitCollection
. Также отмечено, что документация Apple не рекомендует переопределятьtraitCollection
, поэтому в будущем могут возникнуть проблемы с этим методом.источник
traitCollection
свойство должно бытьДлинный и полезный ответ RonDiamond - хорошее начало для понимания принципов, однако код, который работал у меня (iOS 8+), основан на методе переопределения
(UITraitCollection *)traitCollection
Итак, добавьте ограничения в InterfaceBuilder с вариациями для Width - Compact, например, для свойства ограничения Installed. Таким образом, Ширина - Любая будет допустима для альбомной ориентации, Ширина - Компактная - для Книжной.
Чтобы переключить ограничения в коде в зависимости от текущего размера контроллера представления, просто добавьте в свой класс UIViewController следующее:
источник
Насколько ваш альбомный режим будет отличаться от портретного? Если он сильно отличается, было бы неплохо создать другой контроллер представления и загрузить его, когда устройство находится в альбомной ориентации.
Например
источник
Версия Swift 5. Работает нормально.
источник
Код Swift 3.0 для решения @RonDiamond
источник