Wygląda na to, że intencją Apple jest traktowanie obu orientacji iPada jako tej samej - ale jak wielu z nas odkrywa, istnieją bardzo uzasadnione powody projektowe, aby chcieć zmienić układ interfejsu użytkownika dla iPad Portrait i iPad Landscape.
Niestety, wydaje się, że obecny system operacyjny nie zapewnia wsparcia dla tego rozróżnienia ... co oznacza, że wracamy do manipulowania ograniczeniami automatycznego układu w kodzie lub podobnych obejść, aby osiągnąć to, co powinniśmy uzyskać za darmo za pomocą Adaptive UI .
Nie jest to eleganckie rozwiązanie.
Nie jest jakiś sposób wykorzystać magię, że Apple jest już wbudowany w IB i UIKit użyć klasy wielkości naszego wyboru dla danej orientacji?
~
Myśląc o problemie bardziej ogólnie, zdałem sobie sprawę, że „klasy rozmiarów” to po prostu sposoby rozwiązania wielu układów przechowywanych w IB, tak aby można je było wywoływać w razie potrzeby w czasie wykonywania.
W rzeczywistości „klasa wielkości” to tak naprawdę tylko para wartości wyliczeniowych. Z UIInterface.h:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
Więc niezależnie od tego, co Apple zdecydowało się nazwać te różne odmiany, zasadniczo są one tylko parą liczb całkowitych używanych jako swoisty unikalny identyfikator, aby odróżnić jeden układ od drugiego, przechowywany w IB.
Teraz, zakładając, że utworzymy alternatywny układ (używając nieużywanej klasy rozmiaru) w IB - powiedzmy, dla iPad Portrait ... czy istnieje sposób, aby urządzenie użyło naszej wybranej klasy rozmiaru (układu interfejsu użytkownika) w razie potrzeby w czasie wykonywania ?
Po wypróbowaniu kilku różnych (mniej eleganckich) podejść do problemu, podejrzewałem, że może istnieć sposób na programowe zastąpienie domyślnej klasy rozmiaru. I jest (w 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);
Tak więc, jeśli możesz spakować swoją hierarchię kontrolera widoku jako `` podrzędny '' kontroler widoku i dodać go do nadrzędnego kontrolera widoku najwyższego poziomu ... wtedy możesz warunkowo zastąpić dziecko myśląc, że jest to inna klasa rozmiaru niż domyślna z systemu operacyjnego.
Oto przykładowa implementacja, która to robi w kontrolerze widoku „nadrzędnego”:
@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
Aby szybko sprawdzić, czy to zadziałało, dodałem niestandardowe etykiety specjalnie do wersji „Regular / Regular” i „Compact / Regular” układu kontrolera podrzędnego w IB:
A oto jak wygląda bieganie, gdy iPad jest w obu orientacjach:
Voila! Konfiguracje klas rozmiaru niestandardowego w czasie wykonywania.
Miejmy nadzieję, że Apple uczyni to niepotrzebnym w następnej wersji systemu operacyjnego. W międzyczasie może to być bardziej eleganckie i skalowalne podejście niż programowe manipulowanie ograniczeniami automatycznego układu lub wykonywanie innych operacji w kodzie.
~
EDYCJA (6/4/15): Należy pamiętać, że powyższy przykładowy kod jest zasadniczo dowodem słuszności koncepcji w celu zademonstrowania techniki. Możesz dowolnie dostosowywać się do własnych potrzeb.
~
EDYCJA (24.07.15): To satysfakcjonujące, że powyższe wyjaśnienie wydaje się pomóc w wyjaśnieniu problemu. Chociaż tego nie testowałem, kod mohamede1945 [poniżej] wygląda na przydatną optymalizację do celów praktycznych. Zapraszam do przetestowania i daj nam znać, co myślisz. (Ze względu na kompletność pozostawię powyższy przykładowy kod bez zmian).