Tampaknya niat Apple untuk memperlakukan kedua orientasi iPad sebagai hal yang sama - tetapi seperti yang banyak dari kita temukan, ada alasan desain yang sangat sah untuk ingin memvariasikan tata letak UI untuk iPad Portrait vs iPad Landscape.
Sayangnya, OS saat ini tampaknya tidak memberikan dukungan untuk perbedaan ini ... yang berarti bahwa kami kembali memanipulasi batasan tata letak otomatis dalam kode atau solusi serupa untuk mencapai apa yang idealnya kami dapatkan secara gratis menggunakan Adaptive UI .
Bukan solusi yang elegan.
Tidakkah ada cara untuk memanfaatkan keajaiban yang telah dibangun Apple ke dalam IB dan UIKit untuk menggunakan kelas ukuran yang kita pilih untuk orientasi tertentu?
~
Dalam memikirkan masalah secara lebih umum, saya menyadari bahwa 'kelas ukuran' hanyalah cara untuk menangani beberapa tata letak yang disimpan di IB, sehingga dapat dipanggil sesuai kebutuhan pada waktu proses.
Faktanya, 'kelas ukuran' sebenarnya hanyalah sepasang nilai enum. Dari UIInterface.h:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
Jadi terlepas dari apa yang Apple putuskan untuk memberi nama variasi yang berbeda ini, pada dasarnya, mereka hanyalah sepasang bilangan bulat yang digunakan sebagai pengenal unik, untuk membedakan satu tata letak dari yang lain, disimpan di IB.
Sekarang, misalkan kita membuat tata letak alternatif (menggunakan kelas ukuran yang tidak terpakai) di IB - katakanlah, untuk Potret iPad ... adakah cara agar perangkat menggunakan pilihan kelas ukuran (tata letak UI) sesuai kebutuhan saat runtime ?
Setelah mencoba beberapa pendekatan berbeda (kurang elegan) untuk masalah ini, saya menduga mungkin ada cara untuk menimpa kelas ukuran default secara terprogram. Dan ada (di 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);
Jadi, jika Anda dapat mengemas hierarki pengontrol tampilan sebagai pengontrol tampilan 'anak', dan menambahkannya ke pengontrol tampilan induk tingkat atas ... Anda dapat mengganti secara bersyarat anak tersebut dengan berpikir bahwa itu adalah kelas ukuran yang berbeda dari default dari OS.
Berikut adalah contoh implementasi yang melakukan ini, di pengontrol tampilan 'induk':
@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
Sebagai demo cepat untuk melihat apakah itu berhasil, saya menambahkan label khusus secara khusus ke versi 'Reguler / Reguler' dan 'Ringkas / Reguler' dari tata letak pengontrol anak di IB:
Dan inilah yang tampak seperti berjalan, saat iPad berada dalam kedua orientasi:
Voila! Konfigurasi kelas ukuran khusus pada waktu proses.
Semoga Apple akan membuat ini tidak perlu di OS versi berikutnya. Sementara itu, ini mungkin pendekatan yang lebih elegan dan skalabel daripada mengotak-atik batasan tata letak otomatis atau melakukan manipulasi lain dalam kode secara terprogram.
~
EDIT (6/4/15): Harap diingat bahwa contoh kode di atas pada dasarnya adalah bukti konsep untuk mendemonstrasikan teknik tersebut. Jangan ragu untuk beradaptasi sesuai kebutuhan untuk aplikasi spesifik Anda sendiri.
~
EDIT (7/24/15): Sangat menyenangkan bahwa penjelasan di atas tampaknya membantu mengungkap masalah. Meskipun saya belum mengujinya, kode oleh mohamede1945 [di bawah] tampak seperti pengoptimalan yang berguna untuk tujuan praktis. Jangan ragu untuk mengujinya dan beri tahu kami pendapat Anda. (Demi kelengkapan, saya akan membiarkan kode contoh di atas apa adanya.)