Adaptive UIPresentationController Based on View Size
Asked Answered
W

3

15

I'm moving over to UIPresentationController based presentations for my view controllers but have run into some confusion with the API.

I have a custom sidebar style view controller presentation (similar to the LookInside WWDC 2014 demo code).

This class cluster (UIPresentationController, UIViewControllerTransitioningDelegate, and UIViewControllerAnimatedTransitioning) presents a view controller as a sidebar from the edge of the screen on regular size class views, and presents the same view controller as full screen on compact size class views.

Testing this on the Resizable iPad target shows the correct behaviour: I set the horizontal size class to "Compact" and my view controller switches from sidebar to full screen.

However, I want more granularity. I would like to use the sidebar-style view controller presentation on iPhone 6 and 6+ when the device is in landscape orientation, and use the full-screen style presentation for all iPhones in portrait orientation.

So in my method

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

I implemented some logic to detect whether the sidebar will occupy too much of the screen, let's say I use the following condition:

//If my sidebar is going to occupy more than half the new width of the view...
if( self.sidebarTransitionController.width > size.width / 2.0 )
{
    //Override the presentation controller's trait collection with Compact horizontal size class
    sidebarPresentationController.overrideTraitCollection = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];
}
else
{
    //Otherwise override the trait collection with Regular
    sidebarPresentationController.overrideTraitCollection = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];

}

However this does nothing. The documentation for UIPresentationController.overrideTraitCollection states:

Use this property to specify any traits that you want to apply to the presented and presenting view controllers. The traits you specify override any existing traits currently in effect for the view controllers. The default value of this property is nil.

Assigning a new value to this property causes the presentation controller to transition to the new set of traits, which could result in animations to the presented interface.

Assigning the new value to the presentation controller does not cause my presented interface to change in any way. (Even if I assign the overrideTraitCollection when the UIPresentationController is created from within the UIViewControllerTransitioningDelegate object.)

What am I missing? Is it possible to perform adaptive presentation with UIPresentationController on a more granular level?

Wastrel answered 9/4, 2015 at 13:28 Comment(0)
M
2

Is it possible to perform adaptive presentation with UIPresentationController on a more granular level?

Not easily.

I suggest one of these options:

  1. Give up on control and accept UIKit’s limited adaptivity: you can change to a full screen presentation or present a different view controller for a particular trait collection. Go with this to ship your app faster.

  2. Use presentations but work against UIKit. One way is to override viewWillTransitionToSize:withTransitionCoordinator: and dismiss and then re-present the presented view controller, making any changes you want such as providing a different presentation style or presentation controller. This could give okay results without taking too much time.

  3. Use view controller containment. This is about the lowest level you can go while sticking with UIKit best practices. Your main view controller becomes a child of a container view controller, and instead of presenting you ask the container to show the other view controller. Go with this if the app should be custom and exquisite, and you can spend the time to make it just right.

Martinmartina answered 18/8, 2015 at 15:13 Comment(0)
K
1

Use:

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
                                                               traitCollection:(UITraitCollection *)traitCollection NS_AVAILABLE_IOS(8_3);

It's called on rotation even if the size class hasn't changed so is a good place to do you idiom/orientation specific adaptation. Remember that iPhone 6 can run in zoomed in mode.

Krispin answered 5/3, 2016 at 3:18 Comment(0)
B
0

I was running into the same issue. It's possible to interpret device orientation from the size classes, although not completely unambiguously, but the following worked for my purposes.

From Programming iOS 9: Dive Deep into Views, View Controllers and Frameworks, an excellent book full of important details like this:

horizontalSizeClass, verticalSizeClass

A UIUserInterfaceSizeClass value, either .Regular or .Compact. These are called size classes. The size classes, in combination, have the following meanings:

Both vertical and horizontal size classes are .Regular: We're running on an iPad

The vertical size class is .Regular, but the horizontal size class is .Compact: We're running on an iPhone with the app in portrait orientation. (Alternatively we might be running on an iPad in a splitscreen iPad multitasking configuration; see Chapter 9).

Both the vertical and horizontal size classes are .Compact: We're running on an iPhone (except iPhone 6 plus) with the app in landscape orientation.

The vertical size class is .Compact and the horizontal size class is .Regular: We're running on an iPhone 6 plus in landscape orientation.

e.g. in the View Controller:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "ShowComposeView" {
        segue.destinationViewController.presentationController!.delegate = self
        segue.destinationViewController.modalPresentationStyle = .PageSheet
    }
}

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
    // If we do an adaptive presentation, and adapt from Page Sheet to Form Sheet,
    // then on iPhone 6 we will get the nice rounded corners of the nav bar 
    // in both portrait and landscape. (From pg. 298 of Programming iOS 9)

    // We want this behaviour on iPhone in Portrait orientation only.
    if traitCollection.horizontalSizeClass == .Compact && traitCollection.verticalSizeClass == .Regular {
        return .FormSheet
    }
    else {
        return .PageSheet
    }
}
Baseler answered 8/4, 2016 at 4:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.