Parece que la intención de Apple es tratar ambas orientaciones del iPad de la misma manera, pero como algunos de nosotros estamos descubriendo, existen razones de diseño muy legítimas para querer variar el diseño de la interfaz de usuario para iPad vertical frente a iPad horizontal.
Desafortunadamente, el sistema operativo actual no parece brindar soporte para esta distinción ... lo que significa que volvemos a manipular las restricciones de diseño automático en el código o soluciones alternativas similares para lograr lo que idealmente deberíamos poder obtener de forma gratuita utilizando la interfaz de usuario adaptable .
No es una solución elegante.
¿No hay una manera de aprovechar la magia que Apple ya ha incorporado en IB y UIKit para usar una clase de tamaño de nuestra elección para una orientación determinada?
~
Al pensar en el problema de manera más genérica, me di cuenta de que las 'clases de tamaño' son simplemente formas de abordar varios diseños que se almacenan en IB, de modo que se puedan llamar según sea necesario en tiempo de ejecución.
De hecho, una 'clase de tamaño' es en realidad solo un par de valores de enumeración. Desde UIInterface.h:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
Entonces, independientemente de cómo Apple haya decidido nombrar estas diferentes variaciones, fundamentalmente, son solo un par de números enteros que se usan como una especie de identificador único, para distinguir un diseño de otro, almacenado en IB.
Ahora, suponiendo que creamos un diseño alternativo (usando una clase de tamaño no utilizada) en IB, digamos, para iPad Portrait ... ¿hay alguna manera de que el dispositivo use nuestra elección de clase de tamaño (diseño de interfaz de usuario) según sea necesario en tiempo de ejecución? ?
Después de probar varios enfoques diferentes (menos elegantes) del problema, sospeché que podría haber una forma de anular la clase de tamaño predeterminada mediante programación. Y hay (en 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);
Por lo tanto, si puede empaquetar la jerarquía de su controlador de vista como un controlador de vista 'secundario' y agregarlo a un controlador de vista principal de nivel superior ... entonces puede anular condicionalmente al niño para que piense que es una clase de tamaño diferente al predeterminado desde el sistema operativo.
Aquí hay una implementación de muestra que hace esto, en el controlador de vista 'padre':
@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 demostración rápida para ver si funcionaba, agregué etiquetas personalizadas específicamente a las versiones 'Regular / Regular' y 'Compacta / Regular' del diseño del controlador secundario en IB:
Y así es como se ve funcionando, cuando el iPad está en ambas orientaciones:
¡Voila! Configuraciones de clases de tamaño personalizado en tiempo de ejecución.
Con suerte, Apple hará que esto sea innecesario en la próxima versión del sistema operativo. Mientras tanto, este puede ser un enfoque más elegante y escalable que jugar programáticamente con restricciones de diseño automático o hacer otras manipulaciones en el código.
~
EDITAR (4/6/15): tenga en cuenta que el código de muestra anterior es esencialmente una prueba de concepto para demostrar la técnica. Siéntase libre de adaptarse según sea necesario para su propia aplicación específica.
~
EDITAR (24/7/15): Es gratificante que la explicación anterior parezca ayudar a desmitificar el problema. Aunque no lo he probado, el código de mohamede1945 [abajo] parece una optimización útil para propósitos prácticos. No dude en probarlo y hacernos saber lo que piensa. (En aras de la integridad, dejaré el código de muestra anterior como está).