Похоже, что Apple намерена рассматривать обе ориентации iPad как одну и ту же, но, как некоторые из нас находят, есть вполне законные причины дизайна, чтобы захотеть изменить макет пользовательского интерфейса для iPad Portrait и iPad Landscape.
К сожалению, текущая ОС, похоже, не поддерживает это различие ... это означает, что мы вернулись к манипулированию ограничениями автоматической компоновки в коде или аналогичными обходными путями для достижения того, что мы в идеале должны иметь возможность получить бесплатно с помощью адаптивного пользовательского интерфейса. .
Не изящное решение.
Разве нет способа использовать магию, которую Apple уже встроила в IB и UIKit, чтобы использовать размерный класс по нашему выбору для данной ориентации?
~
Обдумывая проблему в более общем плане, я понял, что «классы размера» - это просто способы обратиться к нескольким макетам, хранящимся в IB, чтобы их можно было вызывать по мере необходимости во время выполнения.
Фактически, «размерный класс» - это просто пара значений перечисления. Из UIInterface.h:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
Итак, независимо от того, как Apple решила назвать эти разные варианты, по сути, это просто пара целых чисел, используемых в качестве своего рода уникального идентификатора, чтобы отличить один макет от другого, хранящегося в IB.
Теперь предположим, что мы создаем альтернативный макет (с использованием неиспользуемого класса размера) в IB - скажем, для iPad Portrait ... есть ли способ заставить устройство использовать наш выбор класса размера (макет пользовательского интерфейса) по мере необходимости во время выполнения ?
Попробовав несколько различных (менее элегантных) подходов к проблеме, я подозревал, что есть способ программно переопределить класс размера по умолчанию. И есть (в UIViewController.h):
// Call to modify the trait collection for child view controllers.
- (void)setOverrideTraitCollection:(UITraitCollection *)collection forChildViewController:(UIViewController *)childViewController NS_AVAILABLE_IOS(8_0);
- (UITraitCollection *)overrideTraitCollectionForChildViewController:(UIViewController *)childViewController NS_AVAILABLE_IOS(8_0);
Таким образом, если вы можете упаковать иерархию контроллера представления как «дочерний» контроллер представления и добавить его к родительскому контроллеру представления верхнего уровня ... тогда вы можете условно переопределить дочерний элемент, думая, что это класс другого размера, чем класс по умолчанию из ОС.
Вот пример реализации, которая делает это в «родительском» контроллере представления:
@interface RDTraitCollectionOverrideViewController : UIViewController {
BOOL _willTransitionToPortrait;
UITraitCollection *_traitCollection_CompactRegular;
UITraitCollection *_traitCollection_AnyAny;
}
@end
@implementation RDTraitCollectionOverrideViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpReferenceSizeClasses];
}
- (void)setUpReferenceSizeClasses {
UITraitCollection *traitCollection_hCompact = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];
UITraitCollection *traitCollection_vRegular = [UITraitCollection traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassRegular];
_traitCollection_CompactRegular = [UITraitCollection traitCollectionWithTraitsFromCollections:@[traitCollection_hCompact, traitCollection_vRegular]];
UITraitCollection *traitCollection_hAny = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassUnspecified];
UITraitCollection *traitCollection_vAny = [UITraitCollection traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassUnspecified];
_traitCollection_AnyAny = [UITraitCollection traitCollectionWithTraitsFromCollections:@[traitCollection_hAny, traitCollection_vAny]];
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
_willTransitionToPortrait = self.view.frame.size.height > self.view.frame.size.width;
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]
_willTransitionToPortrait = size.height > size.width;
}
-(UITraitCollection *)overrideTraitCollectionForChildViewController:(UIViewController *)childViewController {
UITraitCollection *traitCollectionForOverride = _willTransitionToPortrait ? _traitCollection_CompactRegular : _traitCollection_AnyAny;
return traitCollectionForOverride;
}
@end
В качестве быстрой демонстрации, чтобы увидеть, работает ли это, я добавил настраиваемые метки специально для версий 'Regular / Regular' и 'Compact / Regular' макета дочернего контроллера в IB:
А вот как это выглядит, когда iPad находится в обеих ориентациях:
Вуаля! Конфигурации классов нестандартного размера во время выполнения.
Надеюсь, Apple сделает это ненужным в следующей версии ОС. Между тем, это может быть более элегантный и масштабируемый подход, чем программная возня с ограничениями автоматической компоновки или выполнение других манипуляций в коде.
~
РЕДАКТИРОВАТЬ (6/4/15): имейте в виду, что приведенный выше образец кода по сути является доказательством концепции для демонстрации техники. Не стесняйтесь при необходимости адаптироваться к вашему конкретному приложению.
~
РЕДАКТИРОВАТЬ (7/24/15): отрадно, что приведенное выше объяснение, похоже, помогает прояснить проблему. Хотя я не тестировал его, код mohamede1945 [ниже] выглядит как полезная оптимизация для практических целей. Не стесняйтесь протестировать его и сообщить нам, что вы думаете. (Для полноты картины я оставлю приведенный выше пример кода как есть.)