Distinguish iPad orientation with size classes

2019-02-23 08:14发布

With iOS 8 Apple introduced size classes for handling layouts of an app. Instead of designing user interfaces dependent on device, screen size, and orientation, developers are encouraged to rather adapt their app's layout depending on the active size classes. That's a good move, I think.

However, when it comes to the iPad there seem to be no way to distinguish the different device orientations (which provide quite different screen space and handling in my opinion). From the Human Interface Guidelines: iPad Size Classes What am I supposed to do now if I want to present a side menu only in landscape orientation because it provides more space, like a UISplitViewController?

Is the UISplitViewController another case where Apple doesn't eat it's own dog food and uses some other metrics like the device orientation or the actual screen width to determine the layout? Or is there another, official way to do that? Something I could do in Interface Builder alone without code?

(And no, I don't want to use UISplitViewController for several reasons.)

1条回答
干净又极端
2楼-- · 2019-02-23 08:26

This is how I resolved the issue you're having:

Use a different size class to add the constraints for portrait and landscape (which you seem to be doing) then create an IBOutletCollection for the constraints for each size class that are based on the orientation.

For example, I used wAnyhRegular to setup my portrait iPad layout and then used wRegularhAny to setup my landscape iPad layout. (Although you may want to use wRegular/hRegular as one of your orientation layouts since iPad registers as wRegular/hRegular when you check the UITraitCollection. Hopefully the code below demonstrates how I went about it:

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *iPadPortraitConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *iPadLandscapeConstraints;

My portrait constraints can be seen below. My landscape has 3 constraints as well. Portrait Constraints

I then apply the constraints as noted below (not shown, viewDidLoad executes _needsiPadConstraintsApplied = YES;):

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    [self applyiPadConstraints];
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    //  Size Classes does not support differentiating between iPad Portrait & Landscape.
    //  Signal that the iPad rotated so we can manually change the constraints.
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        _needsiPadConstraintsApplied = YES;
    }
}
- (void)applyiPadConstraints {

    if (_needsiPadConstraintsApplied) {

        if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) {
            [NSLayoutConstraint deactivateConstraints:self.iPadLandscapeConstraints];
            [NSLayoutConstraint activateConstraints:self.iPadPortraitConstraints];

        } else {
            [NSLayoutConstraint deactivateConstraints:self.iPadPortraitConstraints];
            [NSLayoutConstraint activateConstraints:self.iPadLandscapeConstraints];
        }

        _needsiPadConstraintsApplied = NO;
    }
}
查看更多
登录 后发表回答