Parece que a intenção da Apple é tratar as duas orientações do iPad como iguais - mas, como vários de nós estamos descobrindo, há razões de design muito legítimas para querer variar o layout da IU para iPad Retrato vs. iPad Paisagem.
Infelizmente, o sistema operacional atual não parece fornecer suporte para essa distinção ... o que significa que estamos de volta à manipulação de restrições de layout automático no código ou soluções alternativas para alcançar o que deveríamos idealmente conseguir gratuitamente usando Adaptive UI .
Não é uma solução elegante.
Não há uma maneira de aproveitar a magia que a Apple já incorporou ao IB e ao UIKit para usar uma classe de tamanho de nossa escolha para uma determinada orientação?
~
Ao pensar sobre o problema de forma mais genérica, percebi que 'classes de tamanho' são simplesmente maneiras de lidar com vários layouts armazenados em IB, para que possam ser chamados conforme necessário no tempo de execução.
Na verdade, uma 'classe de tamanho' é apenas um par de valores enum. De UIInterface.h:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
Portanto, independentemente de como a Apple decidiu nomear essas variações diferentes, fundamentalmente, eles são apenas um par de números inteiros usados como uma espécie de identificador único, para distinguir um layout de outro, armazenado em IB.
Agora, supondo que criemos um layout alternativo (usando uma classe de tamanho não utilizada) em IB - digamos, para iPad Portrait ... há uma maneira de fazer com que o dispositivo use nossa escolha de classe de tamanho (layout de IU) conforme necessário no tempo de execução ?
Depois de tentar várias abordagens diferentes (menos elegantes) para o problema, suspeitei que poderia haver uma maneira de substituir a classe de tamanho padrão programaticamente. E há (em 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);
Assim, se você pode empacotar sua hierarquia de controlador de visão como um controlador de visão 'filho', e adicioná-lo a um controlador de visão pai de nível superior ... então você pode sobrescrever condicionalmente o filho fazendo-o pensar que é uma classe de tamanho diferente do padrão do sistema operacional.
Aqui está um exemplo de implementação que faz isso, no controlador de visualização 'pai':
@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
Como uma demonstração rápida para ver se funcionava, adicionei rótulos personalizados especificamente às versões 'Regular / Regular' e 'Compacto / Regular' do layout do controlador filho em IB:
E é assim que funciona, quando o iPad está nas duas orientações:
Voila! Configurações de classe de tamanho personalizado em tempo de execução.
Esperançosamente, a Apple tornará isso desnecessário na próxima versão do sistema operacional. Enquanto isso, essa pode ser uma abordagem mais elegante e escalonável do que mexer programaticamente com restrições de layout automático ou fazer outras manipulações no código.
~
EDIT (6/4/15): Por favor, tenha em mente que o código de exemplo acima é essencialmente uma prova de conceito para demonstrar a técnica. Sinta-se à vontade para adaptar conforme necessário para sua aplicação específica.
~
EDIT (24/07/15): É gratificante que a explicação acima pareça ajudar a desmistificar o problema. Embora eu não tenha testado, o código de mohamede1945 [abaixo] parece uma otimização útil para fins práticos. Sinta-se à vontade para testar e nos dar sua opinião. (Para fins de integridade, deixarei o código de exemplo acima como está.)