Có vẻ như ý định của Apple là coi cả hai hướng của iPad là giống nhau - nhưng như một số người trong chúng ta đang nhận thấy, có những lý do thiết kế rất chính đáng để muốn thay đổi bố cục giao diện người dùng cho iPad Portrait so với iPad Landscape.
Thật không may, hệ điều hành hiện tại dường như không cung cấp hỗ trợ cho sự khác biệt này ... có nghĩa là chúng ta đang quay lại thao tác với các ràng buộc bố cục tự động trong mã hoặc các cách giải quyết tương tự để đạt được những gì chúng ta lý tưởng có thể nhận được miễn phí bằng Giao diện người dùng thích ứng .
Không phải là một giải pháp thanh lịch.
Không có cách nào để tận dụng điều kỳ diệu mà Apple đã tích hợp sẵn trong IB và UIKit để sử dụng loại kích thước do chúng tôi lựa chọn cho một định hướng nhất định?
~
Khi suy nghĩ về vấn đề một cách tổng quát hơn, tôi nhận ra rằng 'các lớp kích thước' chỉ đơn giản là cách để giải quyết nhiều bố cục được lưu trữ trong IB, để chúng có thể được gọi lên khi cần thiết trong thời gian chạy.
Trên thực tế, một 'size class' thực sự chỉ là một cặp giá trị enum. Từ UIInterface.h:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
Vì vậy, bất kể Apple đã quyết định đặt tên cho các biến thể khác nhau này là gì, về cơ bản, chúng chỉ là một cặp số nguyên được sử dụng làm mã định danh duy nhất để phân biệt bố cục này với bố cục khác, được lưu trữ trong IB.
Bây giờ, giả sử rằng chúng tôi tạo bố cục thay thế (sử dụng loại kích thước không được sử dụng) trong IB - giả sử, đối với iPad Portrait ... có cách nào để thiết bị sử dụng lựa chọn loại kích thước (bố cục giao diện người dùng) của chúng tôi khi cần thiết trong thời gian chạy không ?
Sau khi thử một số cách tiếp cận khác nhau (ít thanh lịch hơn) cho vấn đề, tôi nghi ngờ có thể có một cách để ghi đè lớp kích thước mặc định theo chương trình. Và có (trong 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);
Do đó, nếu bạn có thể đóng gói hệ thống phân cấp bộ điều khiển chế độ xem của mình dưới dạng bộ điều khiển chế độ xem 'con' và thêm nó vào bộ điều khiển chế độ xem cấp cao nhất ... thì bạn có thể ghi đè có điều kiện để trẻ nghĩ rằng đó là một lớp kích thước khác với mặc định từ hệ điều hành.
Đây là một triển khai mẫu thực hiện điều này, trong bộ điều khiển chế độ xem 'cha':
@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
Như một bản trình diễn nhanh để xem liệu nó có hoạt động hay không, tôi đã thêm các nhãn tùy chỉnh cụ thể vào phiên bản 'Thông thường / Thông thường' và 'Nhỏ gọn / Thông thường' của bố cục bộ điều khiển con trong IB:
Và đây là những gì nó trông giống như đang chạy, khi iPad ở cả hai hướng:
Thì đấy! Cấu hình lớp kích thước tùy chỉnh trong thời gian chạy.
Hy vọng rằng Apple sẽ biến điều này trở nên không cần thiết trong phiên bản tiếp theo của hệ điều hành. Trong thời gian chờ đợi, đây có thể là một cách tiếp cận thanh lịch và có thể mở rộng hơn là việc lập trình gây rối với các ràng buộc bố cục tự động hoặc thực hiện các thao tác khác trong mã.
~
EDIT (6/4/15): Xin lưu ý rằng mã mẫu ở trên về cơ bản là một bằng chứng khái niệm để chứng minh kỹ thuật. Hãy tự do điều chỉnh nếu cần cho ứng dụng cụ thể của riêng bạn.
~
EDIT (24/7/15): Thật vui vì lời giải thích ở trên dường như giúp làm sáng tỏ vấn đề. Mặc dù tôi chưa thử nghiệm nó, nhưng mã của mohamede1945 [bên dưới] trông giống như một tối ưu hóa hữu ích cho các mục đích thực tế. Hãy thử nó ra và cho chúng tôi biết suy nghĩ của bạn. (Vì sự hoàn chỉnh, tôi sẽ để nguyên mã mẫu ở trên.)