Es scheint Apples Absicht zu sein, beide iPad-Ausrichtungen als gleich zu behandeln - aber wie einige von uns feststellen, gibt es sehr legitime Designgründe, das UI-Layout für iPad Portrait im Vergleich zu iPad Landscape variieren zu wollen.
Leider scheint das aktuelle Betriebssystem diese Unterscheidung nicht zu unterstützen ... was bedeutet, dass wir wieder die Einschränkungen des automatischen Layouts in Code oder ähnlichen Problemumgehungen bearbeiten, um das zu erreichen, was wir idealerweise mit der adaptiven Benutzeroberfläche kostenlos erhalten sollten .
Keine elegante Lösung.
Gibt es nicht eine Möglichkeit, die Magie, die Apple bereits in IB und UIKit eingebaut hat, zu nutzen, um eine Größenklasse unserer Wahl für eine bestimmte Ausrichtung zu verwenden?
~
Als ich allgemeiner über das Problem nachdachte, wurde mir klar, dass 'Größenklassen' einfach Möglichkeiten sind, mehrere in IB gespeicherte Layouts zu adressieren, damit sie zur Laufzeit nach Bedarf aufgerufen werden können.
Tatsächlich ist eine 'Größenklasse' nur ein Paar von Aufzählungswerten. Von UIInterface.h:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
Also unabhängig davon , was Apple hat beschlossen, nennt diese verschiedenen Variationen, im Grunde sind sie nur ein Paar von ganzen Zahlen als eindeutige Kennung der Art verwendet, ein Layout von einem anderen zu unterscheiden, in IB gespeichert.
Angenommen, wir erstellen in IB ein alternatives Layout (unter Verwendung einer nicht verwendeten Größenklasse) - beispielsweise für iPad Portrait ... gibt es eine Möglichkeit, das Gerät zur Laufzeit nach Bedarf die von uns gewählte Größenklasse (UI-Layout) verwenden zu lassen ?
Nachdem ich verschiedene (weniger elegante) Ansätze für das Problem ausprobiert hatte, vermutete ich, dass es eine Möglichkeit gibt, die Standardgrößenklasse programmgesteuert zu überschreiben. Und es gibt (in 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);
Wenn Sie also Ihre View-Controller-Hierarchie als untergeordneten View-Controller verpacken und zu einem übergeordneten View-Controller der obersten Ebene hinzufügen können, können Sie das untergeordnete Element unter der Bedingung überschreiben, dass es sich um eine andere Größenklasse als die Standardgröße handelt vom Betriebssystem.
Hier ist eine Beispielimplementierung, die dies im übergeordneten Ansichtscontroller tut:
@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
Als schnelle Demo, um zu sehen, ob es funktioniert hat, habe ich benutzerdefinierte Beschriftungen speziell zu den Versionen 'Regular / Regular' und 'Compact / Regular' des untergeordneten Controller-Layouts in IB hinzugefügt:
Und so sieht es beim Laufen aus, wenn sich das iPad in beiden Richtungen befindet:
Voila! Benutzerdefinierte Größenklassenkonfigurationen zur Laufzeit.
Hoffentlich macht Apple dies in der nächsten Version des Betriebssystems unnötig. In der Zwischenzeit ist dies möglicherweise ein eleganterer und skalierbarer Ansatz als das programmgesteuerte Durcheinander mit Einschränkungen beim automatischen Layout oder andere Manipulationen im Code.
~
EDIT (6/4/15): Bitte beachten Sie, dass der obige Beispielcode im Wesentlichen ein Proof of Concept ist die Technik zu demonstrieren. Sie können sich jederzeit an Ihre spezifische Anwendung anpassen.
~
EDIT (24.07.15): Es ist erfreulich, dass die obige Erklärung dazu beiträgt, das Problem zu entmystifizieren. Obwohl ich es nicht getestet habe, sieht der Code von mohamede1945 [unten] aus praktischen Gründen wie eine hilfreiche Optimierung aus. Probieren Sie es einfach aus und teilen Sie uns Ihre Meinung mit. (Der Vollständigkeit halber lasse ich den obigen Beispielcode unverändert.)