A Look Inside Presentation Controllers

A Look Inside Presentation Controllers

Session 228WWDC 2014

iOS 8 brings you powerful new means of presenting content within your apps. Hear how presentation controllers were leveraged by UIKit to give you fine grain control using new alert and searching APIs. Dive deep into how presentation controllers work and how you can use them to present content within your app in exciting new ways.

[ Applause ]

Good morning.

My name is Jim Turner.

And I'm Peter Hajas.

And we're engineers on the UIKit Team.

And welcome to the presentation on A Look Inside Presentation Controllers.

So UIViewController presentations have been around since iOS 2, but only recently have you had the chance to customize them in your apps.

In iOS 7, we introduced the concept of an animator object.

This is an object who's responsible for animating your view controller's content on-screen.

However, if you wanted to build a totally custom view controller presentation, it involved burdening that animator object with far too much responsibility.

So that's why in iOS 8, we're introducing UIPresentationController.

This class is designed to work in concert with animator objects to make the job of presenting view controller content easy and simple to manage and execute.

So today, we're going to talk about just a couple of topics, the first being some presentation basics.

What do we mean by presenting view controller content?

What's the difference between chrome and content itself?

And what do we expect UIPresentationController to be responsible for?

Next, we'll go over how UIKit used UIPresentationController to expand our own API.

And finally, we'll wind up with a demo that brings all these concepts together, so that you guys can see how you can use UIPresentationController in your apps.

First, let's start with some presentation basics.

Here I am, on the Settings app on iPad, and I'm going to tap that Create New Apple ID table cell.

The New Account sheet slides up, and we're ready to go.

In UIViewController terminology, we would call that New Account Sheet the presented view controller.

And the Settings split view behind it, the presenting view controller.

When we talk about the responsibilities of UIPresentationController, we would say that that New Account Sheet is the content of the presentation.

It's the foreground stuff that your user is meant to interact with.

We would then say that the background content that's dimmed is the chrome.

It's dimmed to help accentuate the content of your presentation.

To help manage the content and chrome, in your view controller presentation, we're going to use UIPresentationController.

At its heart, UIPresentationController is the presentation management class that you'll use in your application.

All UI view controller presentations in iOS 8 are backed by UIPresentationController.

Because UIPresentationController can provide chrome, it can also provide its own animations for that chrome or and this is really coolUIPresentationController can animate its chrome alongside your existing animator objects' custom animations.

And we'll take a look at a demo of that.

Additionally, throughout the conference, you've heard about our push to make your applications more adaptive.

And UIPresentationController is built from the get-go to handle trait and size class changes.

Additionally, UIPresentationController will respond to these changes, even while your view controller's presentation is on-screen.

So you can adapt seamlessly between the changing environment.

And finally, because UIPresentationController is a great Cocoa Touch citizen, it's reusable.

UIPresentationController objects are not coupled to animator objects or transitioning delegates.

You can use the same Presentation Controller with different view controllers, or switch out the Presentation Controller for the same view controller to create a truly custom look.

Prior to iOS 8, the animator object, as Peter mentioned, was kind of overburdened with some tasks when presenting a view controller's content on-screen.

Its primary task was obviously animating that controller's content, and that includes any kind of subview animations things like content offsets or insets, as well.

But it also needed to figure out its own positioning on-screen.

If you were doing any kind of custom presentation, we would give you reasonably good information for where to start and where to end, but it's probably not what you wanted for your custom presentation.

And so the animator object had to know more about the presentation than it probably should have.

And that goes along with the chrome, as well.

That animator object also needed to know, the entire layout what the presentation was going to encompass.

But now, with Presentation Controller, this responsibility for positioning that view controller and for handling the chrome and other views that go along with the presentation are handled in a much more logical object.

The Presentation Controller and since it's long-lived knows more about the presentation, because it has a better vantage point for what's actually going to occur on-screen.

And as we have mentioned before, Presentation Controller is what drives adaptation in your application.

This object is going to be responsible for helping you switch out view controllers and wholesale switching out of Presentation Controllers,which we will look at in just a moment.

So now that we know about a little bit about what Presentation Controller actually is, let's show you how we in UIKit used it to improve popovers, alerts, action sheets and search.

And we'll have Peter start you off with popovers.

Sure thing.

As you saw in our talk yesterday, we're introducing a new UIPresentationController class to help manage popover presentations in your app.

It's called UIPopoverPresentationController.

It's intended to replace UIPopoverController in your application, but it is functionally equivalent in the customization that it provides for the presentation.

But it has some additional features.

It has built-in adaptivity to help facilitate your view controller adapting in a changing environment.

UIPopoverPresentationController will seamlessly handle transitions between regular and compact-width environments.

Let's look at how you used to show a popover, prior to iOS 8.

With the old API, you'd create your content view controller, set it on your Popover Controller and present that popover.

But this isn't really the whole story.

If you had a universal application and many of you do you actually had to have two code paths.

We check for it on an iPad and make a popover controller.

Otherwise, we'd do a presentViewController traditionally.

And you had to litter this bifurcation throughout your app.

With UIPopoverPresentationController, you'll just have one code path.

Here's how to use it.

First, you'll set the view controller's modalPresentationStyle to popover.

This is a new value in iOS 8.

UIKit will look to your view controller's modalPresentationStyle to determine how to show your view controller.

Then you'll get its popoverPresentationController.

When presenting a view controller, you do not create a Presentation Controller.

Instead, you ask for one.

Then you set up any source information, like barButtomItems or permittedArrowDirections.

And because it's a view controller presentation, you just call presentViewController.

Now, notice how there's no idiom check on the screen.

That's because, when we're running an environment that does not support popovers, like on the iPhone, UIPopoverPresentationController provides the opportunity for your presentation to adapt.

Jim, can we take a look at adaptive popovers?

Sure.

All right.

So I have a fairly simple and basic application here.

It is a just a view controller that shows important people and the super important people and you click on this little button here, you get a popover.

And it's a popover of super important people.

And so what we want to do is show that this popover, when it goes on in a compact-width environment, like on the iPhone, even though you present as a popover, you will get an adaptation to an over-fullscreen presentation.

So we'll change the width to 320, and we'll change the size class to compact, and we'll apply it.

And then, now you see that we actually have the same table view has been re-presented, but now it's in a view controller that is a full-screen presentation.

And we can actually even dismiss this, and we can re-present it again.

And even though we're re-presenting as an over-fullscreen presentation, we are the code has never changed.

We still actually are presenting a popover here.

And to show that that's actually still working, we'll go back to our regular width.

And then the popover shows back up again.

So to do adaptivity with popovers is fairly simple.

Going back to Peter's code that we left off with is that this code doesn't actually change.

All through that, this was the code that presented that popover.

But to influence how the popover actually works, we need to set a delegate on the popover Presentation Controller.

And we need to implement just two methods.

The first is adaptivePresentationStyle ForPresentationController.

And from this method, you can return one of three different methods FullScreen, OverFullScreen, or none the latter meaning that you don't want any kind of adaptivity, but for here, we want to do a FullScreen adaptation.

The second method that we want to implement is presentationController viewControllerFor AdaptivePresentationStyle.

You don't have to implement this method.

And if we hadn't implemented this method, the table view controller would have been re-presented as a full-screen presentation.

But the table view by itself doesn't allow you to dismiss anything or show the name that we were selecting.

So what we want to do is wrap that view controller in something that allows our presentation to actually continue to look like how we wanted it to look.

And so we wrapped that in a NavigationController, and we just set it as root view controller, the presentedViewController, which was our table view controller.

And that's it.

And that is how you get from a popover in regular width to an over-fullscreen or full-screen presentation, when you're in a compact-width environment.

So now that we've looked at how UIKit used Presentation Controllers to improve the API surrounding popovers, let's talk about something near and dear to my heart: alerts and action sheets.

Prior to iOS 8, alerts and action sheets were exposed to your application through plain UI view subclasses: UIAlertView and UIActionSheet.

But because they were UI view subclasses, they had to re-implement some of the logic that we already had on view controller.

For example, to appear in your application, they created a new window, strategically positioned above your application's content so that they'd show up above everything.

Additionally, they'd pre-date modern language features, so they had to rely on delegate API for button callbacks.

Let's look at how an action sheet presentation worked prior to iOS 8.

So, I'm in an iOS 7 app, in landscape.

And I go to show an action sheet.

Behind the scenes, the framework creates a window on your app's behalf, but this predates iOS 8 window rotation behavior, so this window is technically still in portrait.

We then add the action sheet to that window and mimic the transform hierarchy of the presenting view to get into the right orientation.

When looking at the requirements applications would have to meet when implementing adaptivity and the customization power offered to us by UIPresentationController, it was a natural choice to rebase modern alerts API.

In iOS 8, we're introducing a new View Controller subclass to replace Alert View and Action Sheet UIAlertController.

It's used for both Alerts and Action Sheets, and you can switch via a preferred style.

Additionally, because it's got a modern runtime, it's block-based.

So it works perfect.

[ Applause ]

It works perfect with blocks in Objective-C and closures in SWF.

Additionally, because it's a view controller, it presents in your window, which means that there's no more ambiguity about what framework-provided presentations are going on in your application.

And using the adaptive API that Jim showed you earlier, action sheets will seamlessly adapt to popovers, using popoverPresentationController.

Let's go through how you can create and show an alert controller in your application.

First, you'll ask for one via the class method.

Then you'll add actions to it with a block handler, to handle when that action is tapped.

And then, because it's a view controller presentation, you'll just call presentViewController.

Now, that we've seen how UIKit used Presentation Controller to improve alerts and action sheets, let's see how we did the same thing for search.

Search on iOS 8 consists primarily of two parts: UI search bar and UISearchDisplayController.

Both have been around in the SDK since some of the earliest days.

And their creation was formed at a time that was far more simple.

View controllers were more of a suggestion than the requirement that they are now.

There was far less translucency things didn't flow underneath other things, and there certainly wasn't things like blur to deal with.

And so when you presented search, it was very easy for the framework to reason about how search was going to be displayed in your application.

But when we were looking at SearchDisplayController and how it would react to an adaptive environment, we realize it had some deficiencies that were going to be very difficult to overcome.

The first is that it provides very limited configurability for you guys.

It's great that you can show your search results in a table view, but a lot of other things have happened since iOS 3, that you can show search results in things like collection views and map views.

And SearchDisplayController just simply can't handle this.

Second, SearchDisplayController is not a view controller, although it tries to act like one really hard.

And as the view controller system became more intelligent and more robust, as the SDK matured, the SearchDisplayController had a harder time trying to understand your intent when displaying.

And this left it to have to actually guess, in some situations, and it didn't always get it right.

And finally because again, it's not a view controller its presentation was done via addSubview.

And to show you how horrible this actually was if, in your application this was your search bar, with your content being on the blue, and you tapped that search bar, SearchDisplayController behind the scenes goes and creates a content view, adds a dimming view to it, adds the table view to that and then adds subview to the SearchDisplayController's container or content view or content controller's view.

At this point in time, your application has a view that it didn't expect in its hierarchy, and the framework is trying to manage the fact that that view was probably a scroll view, and things could move around when we don't want it to.

So it's clear that, in adaptivity, this wasn't going to really function all that well.

But, while also looking at this, SearchDisplayController's really just doing a presentation.

I mean, it already had its own container.

So it kind of made sense to rebase this all on top of UIPresentationController.

And that's what we've done.

So in iOS 8, we're introducing UISearchController, which is a view controller-based replacement for the now deprecated UISearchDisplayController.

And it has a number of features, the first of which is that it can present on any view controller in your hierarchy, not just ones that are full-screen.

Second is that the SearchController no longer tries to get in between presenting the thing that's showing the results and the thing that's driving the filtering of the results.

This means that any object in your application that's capable of filtering search results can directly drive the UI that's actually showing up on-screen.

You can influence the search bar animation through a custom animator object.

And because, of course, it's built on Presentation Controller, SearchController has the capacity to become adaptive.

And what this means to you guys, in the end, is its far more control in how search is display in your applications and far fewer assumptions made by the framework when you're doing so.

So taking a look at how we used to do this before iOS 8, we would create a search bar, and we'd give that search bar to SearchDisplayController, but then we'd have to tell the SearchController who the data source and the delegate were for the table view that was going to show the results.

And then finally, we would make the search bar, the table header view of a table view that was already on-screen.

Now under iOS 8, with SearchController, the first thing you'll want to do is create a results controller.

And as I mentioned, this could be absolutely anything a collection view or maybe a view that's custom to just your application.

You give this results controller to the Search Results Controller, and then you tell the SearchController who's going to be responsible for updating the results.

In a lot of cases, this will actually just be the results controller.

But it could be literally any object in your application.

Next, this is the one common code lying between the old world, is that when you take the SearchController search bar, and we add it to the table or set it as the table header view of an existing table view that's on-screen.

Now if you notice, we don't actually present this view controller at any point in time.

And that's because search is usually event-driven.

The user is tapping on the search bar, or they're tapping on a search glyph in your interface.

And so in those cases, SearchController is going to perform an automatic presentation for you, based off of where the search bar is located at on-screen.

Of course, there's a delegate method that allows you to drive this, if you'd like.

But for the most part, the default animations are usually pretty close to what you guys are going to expect.

Finally is one piece of API that's been on UIViewController for some time, and its definesPresentationContext.

When using UISearchController, you're probably going to need to define this on the view controller in which you want search to be presented.

Because SearchController is trying really hard to play nicely with your layout, it needs to know exactly where it is going to be displayed at.

And definesPresentationContext allows it to know where you want it to go.

I'll show you in a real quick example of what I mean here.

Take this example as a fairly common case application.

As the application's root View Controller is a tab bar controller, and as that tab bar's controller is selected to tab, it is displaying a navigation controller.

And the navigation controller's root view controller is our table view controller.

And as we've seen before in the previous examples, this search bar is that table view controller's table view's table header view.

And so, you probably want it to have the same behavior that you've seen before iOS 8, is that when you tap on the search bar, the navigation bar disappears and the search bar takes its place.

And the search results take the place of the table view.

In this example, the table view controller needs to define the presentation context for the SearchController.

If you were to omit this, View Controller Presentation behavior says that we will walk up the chain until we find somebody else who defines a Presentation Context, or we use the root view controller.

And in this case, that would be the tab bar controller.

And so this may actually be what you want, but it's something that you need to be aware of when using the new SearchController, is that you need to tell us where you want it at, or we're just going to go present it on the root view controller.

So now that we've shown you how UIKit is leveraged UIPresentationController what are the benefits to you guys for us having done this work?

Well, first off, it's controllers now, all over the place.

Everything's a controller no matter where you look.

And this is good for you guys.

We are no longer trying to shove their views into your hierarchy, or we're no longer trying to transform windows above everything.

It's controllers.

It's a view controller system, and it allows you very unprecedented control in how these control how these view controllers are displayed in your application.

Additionally, because UIPresentationController provides an excellent abstraction between the content of your presentation and the chrome around it, UIPresentationController provides a natural home for these things to live.

No longer do system-provided view controllers contain their chrome in the view controller.

And finally, adaptivity.

We keep saying this over and over again, but we needed to make our own controllers adaptive for your guys for your guys' applications.

So now alerts and search can adapt with your applications and all the other adaptations that you want to do to make your applications work in this new size class world that we're going into.

So now that we've gone through how UIKit has used these things or used Presentation Controller, let's show a demo that kind of pulls all these concepts together, uses a custom Presentation Controller and a custom animator to make a really cool interface.

Peter?

Let's do it.

I've been working on this awesome new photo management and editing application.

Here we have a collection view.

And when I tap a photo, we're going to do a View Controller Presentation, but it looks different than a default view controller presentation.

You'll notice that the presented view controller slides in from the right, while we dim the rest of the screen.

And when we tap the dimming view or hit the Save button, we'll dismiss.

I'm going to edit this photograph.

Looks great.

So I'll hit Save, and we dismiss that view controller.

We should go through how this presentation uses a custom Presentation Controller and animator object to control placement and animations.

Let's go through how you can build a custom presentation like this in your application.

We're going to start in the root view controller of our app.

You'll notice this P in the corner.

We've added colors and text as a legend, so that you know what controller or object we're talking about.

In the root view controller, we're going to create a new overlay view controller.

This is what you saw, presented as a side bar in the demo we just saw.

Then, because it's a view controller, we'll just call presentViewController.

Now if we had stopped here and not implemented anything custom, what would we get?

Well, we'd have our root view controller, and we go to present, and we get the UIKit default: a slide-up from the bottom, full-screen presentation.

That looks cool, but what we really want is a custom presentation, so that when we present the side bar, it slides in from the right, while we dim the presenting view controller's content.

Let's talk about the objects that are going to be responsible for this custom presentation.

We already know that we have a root view controller and our presented overlay view controller.

In iOS 7, we introduced the concept of a transitioning delegate.

In this presentation, this transitioning delegate will be responsible for providing the animator object, which animates our controller contents on-screen.

This is the same API that we introduced in iOS 7.

But new in iOS 8, this transition delegate will also provide the Presentation Controller.

This is the object that will drive the management of the content and chrome in this presentation.

Let's start with getting that dimming view on- and off-screen.

First, back in our root view controller, we'll create a new transitioning delegate to use for this presentation.

This is the object that provides the animator object and Presentation Controller.

And we'll set that transitioning delegate on our presented overlay view controller.

Now, in our overlay view controller, we'll set our ModalPresentationStyle to Custom.

This indicates to UIKit that we should consult your transitioning delegate for a custom Presentation Controller to use for the presentation.

Inside of our transitioning delegate, we'll need to provide that Presentation Controller by implementing PresentationController for presentedViewController, presentingViewController source ViewController.

Here, we'll return to the Presentation Controller that will be responsible for the lifetime of this view controller's transition.

Let's implement some methods in the Presentation Controller to manage this dimming view.

We're going to implement two methods to coordinate the dimming view.

The first is presentationTransitionWillBegin.

This is called when we're about to do the presentation transition.

Here, we've already set up a dimming view in an int [phonetic], and we'll just set that dimming view's frame to the container view's bounds.

This way, the dimming view is always full-screen.

We'll also set the alpha of the dimmingView to 0, so that it appears fully transparent at the beginning of the animation.

We'll make sure we insert the dimmingView above all the other content in the presentation.

And then, this is really cool.

UIPresentationController can provide its own animations for its chrome in this case, the dimming view or it can animate alongside the existing animations in the animator object.

And that's exactly what we want.

We call the presentedViewController's transitionCoordinator to animate alongside the current transition.

Inside of this block, we'll set the dimming view's alpha to 1.

This way, the animations both begin at the same time and finish at the same time, and it looks great.

Now, let's implement the second method in our Presentation Controller for managing the dimming view: dismissalTransitionWillBegin.

Here, we're going to undo what we did, and presentation transition will begin.

In this case, we'll use the same transitionCoordinator API to animate fading the dimming view to a 0 alpha.

Let's see how this looks.

We go to present.

The dimming view fades in, and it fades away.

Looks great, but we should probably get our presentedViewController on-screen next.

First, we'll need to go back to our transitioning delegate and return a custom animator object.

We'll do this by implementing animationController ForPresentedController, presentingController, sourceController.

This is the API that you used in iOS 7.

Here, we'll return our custom class, which is in charge of this animation.

We'll also implement the inverse of this method dismissal or, I'm sorry -animationController ForDismissedController.

UIKit gives you the power and flexibility of using a different animator object for the presentation and dismissal, but here we'll just use the same one.

Now, as you saw in the demo, that overlay side bar was a third the size of the display.

To size it appropriately, we'll need to implement several methods in our Presentation Controller.

The first is sizeForChildContentContainer withParentContainerSize.

And this method's really simple.

We'll just return a third of our parent's width and our full parent's height, so that we're always a third of the display.

Next, we'll implement frameOfPresentedView InContainerView.

This is where we return to the view controller transitioning system what frame we'd like the presented view to have.

We'll use the same size that we returned fromSizeForChildContent ContainerwithParentContainerSize and set the origin of the presented view's frame to be right-aligned in the container.

Let's see how that looks.

Perfect. The overlay is a third of the display and right-aligned.

But what we also want is when we rotate into landscape, that side bar should always appear as a third of the display.

No problem.

Implementing rotation in Presentation Controller is really simple.

We just need to implement one method: containerViewWillLayoutSubviews.

First, we'll set the dimming views frame so that it's always the full size of the container, even when the container's changing bounds.

Then we'll set the frame of the presented view to the same value we returned, from frameOfPresented ViewInContainerView.

And we're done.

We've handled rotation.

Now that we've seen how view controller's sizing works in Presentation Controllers, it's important to understand the messaging that happensbetween Presentation Controllers and their managed view controllers.

New in iOS 8 is a new protocol, UIContentContainer, and it's implemented by both UIViewController and UIPresentationController.

And it's a collection of methods that describe how the view controller and Presentation Controllers communicate changes in the environment to one another.

And it's important that we talk about these methods in regards to how they flow between each of the objects or between the controllers,because the forwarding is done automatically for you, unless you interfere with it.

And I'll show you why you'd want to do that.

There's a couple of different ideas here, so we'll start off with transitioning to a specific size.

There's two methods specifically here: viewWillTransitionToSize withTransitionCoordinator and, as Peter just showed you,sizeForChildContent Container withParentContainerSize.

These indicate to the view controller or the Presentation Controller that the physical size of the view has actually changed.

And this is best kind of shown through a diagram that shows how the messaging flows through.

So let's give ourselves a root view controller with a couple of child view controllers, and let's have it present a view controller.

It doesn't really matter what it actually is.

And as Peter has mentioned previously, all presentations of view controllers are managed by a Presentation Controller, so we've got to have one of those guys, too.

So now that we have this set up, let's give ourselves a viewWillTransitionToSize call.

Maybe the device rotated, and we're getting a different size or different bounds for that view.

These messages always start with the root view controller.

And from there, that controller will message any child view controllers that it may have.

But the size that we pass to the root view controller is probably not the same size that you want to pass onto the child.

It's probably a smaller size.

So this is where sizeForChildContentContainer withParentContainerSize comes in.

We will ask the root controller to size Child 1, and that method returns a size that we will pass on to Child 1's viewWillTransitionToSize.

We continue along if there are any other child view controllers of this controller.

And then any controllers that are presenting view controllers that means that they have another view controller presented on top of them will have their Presentation Controller called next.

In this case, the root view controllers the child view controllers, excuse me aren't presenting anybody, but the root view controller actually is.

The root view controller is not a container for the Presentation Controller, so the size that gets passed to it is the same size that we gave to the root controller.

But the Presentation Controller is the container for the presented controller.

So we need to ask the Presentation Controller, a sizeForChildContentContainer, passing on to presentedViewController.

The messaging flow is basically has a depth for search.

You start with the root view controller.

Any child controllers that are present will get called, but any controller that is presenting a presenting another controller will have its Presentation Controller messaged and then its presented controller is messaged.

And then, the process repeats again.

If for any reason that you implement one of these methods, and you call super, this messaging still is performed for you.

But if you implement these methods and don't call super, the object or the class that does not pass the message on any of its child controllers or any of its presented Presentation Controllers will no longer get that message.

It's something to be aware of.

Oops, there was one more.

Next up is preferred content size, and there are two items here: preferredContentSize and preferredContentSizeDid ChangeForChildContentContainer.

And this is methodologies for allowing a presented view controller or child view controller to say, "I need more or less size" to its container controller.

A really good example of this is the Notification Center widgets will do this.

Your notification your widget will actually set its own preferred content size, which will message its container to allow the size to change.

Let's show what this looks like in our example.

Say the presented controller wants to grow by 100 points.

So it sets its PreferredContentSize to what it would like.

And because the Presentation Controller is the container controller of the presented controller, it gets the message, PreferredContentSizeDid ChangeForChildContentContainer.

Now, if one of the Child 1 or Child 2 view controllers had requested more size, then the root view controller would have gotten this message.

So it's just messaging up to the container controller.

At this point in time, the container has a decision to make.

Does it want to honor the size request?

And if so, how much of it does it want to honor?

It can simply ignore it, if there's not any space to give.

Or it can say, "Well, you asked for 100 points, and I can give you 50."

If you were going to resize the view, it's important that you call back viewWillTransitionToSize: withTransitionCoordinator back on the viewthat made the request.

And this it's kind of like a receipt for that view controller, to let it know that it requested size, it's gotten a size, or however much size the container gave it.

And it's allowed them to forward that message on to any child containers it may have.

And key, right and the key point here is that after you've sent this message, the container needs to resize the child container, the child view controller.

Sending the message ViewWillTransitionToSize does not actually perform the resize itself.

That's something that the container needs to do.

Finally, our trait collections, and there's one method here, and that is willTransitionToTraitCollection withTransitionCoordinator.

And this has the same kind of messaging semantics as the ViewWillTransitionToSize.

It flows in the same order, and if you don't call through super, the message chain ends there.

If you hadn't seen the talk yesterday on building adaptive applications with UIKit, I highly recommend checking that out, because it goes into trait collections in depth and how they interact with the rest of the system.

But as a really quick overview of what they are, in case you haven't read the documentation, trait collections are simply a collection of key value pairs that describe an environment to a view controller or a view or a screen, and there are four properties: a horizontalSizeClass, which describes width; a vertical size excuse me a verticalSizeClass that describes height; the UserInterfaceIdiom that describes the type of devicethat you're on; and then the scale that decides the scale of the device.

So for an iPhone, in portrait, the horizontalSizeClass is compact.

Its verticalSizeClass is regular.

It's a phone, so it's userInterface of phone, and it has a scale of 2.0.

Now, all these methods are trying to allow you to have your application respond to changes.

But some of you may be the ones that have been paying attention most will probably notice that we have two methods that actually send somewhat the same information.

willTransitionToTraitCollection has the notion of size classes, but we also have this method, viewWillTransitionToSize, that's sending along the size.

So why do we have both of these methods?

That's a great question.

Before I actually tell you why, I need to add two more methods to this.

UIPresentationController's containerViewWillLayoutSubviews and UI View Controller's viewWillLayoutSubviews.

Starting with willTransitionToTraitCollection.

This is intended to be a very coarse-grained control over the layout of your application.

When you receive trait collection changes, it's an indication that the structure the overall structure of your application is probably going to change or needs to be updated.

A great example of this is, of course, adaptivity.

In that example demo I gave you before, where the popover went to full-screen, it's not just a view being swapped out that is view controllersand Presentation Controllers being exchanged wholesale.

That's a significant amount of change to your application's user interface.

But it's not just all about size classes.

Screens could have different scales.

Your view controller can be on the main device screen, which has a scale of 2x, but then an external monitor can have a 1x scale.

And moving that view controller from the primary screen to that secondary screen could completely change how your UI needs to be laid out.

And they're not it's not always about entire UI changing effects.

An example of this would be now in iOS 8, when we go from an iPhone-like device, and we go from a compact-width regular height, and we rotate into a compact-width, compact-height environment, we're going to auto-hide the status bar for you.

And we do that not because there's less space; there's not less physical space of that view controller.

It's that it makes more sense in that situation to remove a status bar, so that your content has more area to display itself.

Next up is viewWillTransitionToSize, and this is the medium-grain control approach for responding to changes.

And as I mentioned before, this is an indication that your view actually has more or less size to deal with and that you should actually add more content or remove content depending on how the size changed.

A great example of this was the child controller requesting more size.

In this case, it's not an indication for that view controller to actually lay itself out.

It's an indication that it needs to actually add more content.

You also get this call on rotation.

With rotation under iOS 8, it's simply a bounds change.

So when you when the device rotates, your view controller will get told that its size will change, and you'll probably see that the width and the height have swapped.

And finally, you'll also see these guys, these messages called when the resizable simulator changes its size.

So when you're playing around with the simulator, you'll see that, as well.

Finally, is containerViewWillLayoutSubviews and viewWillLayoutSubviews, and these are the fine-grain controls on UIPresentationController and UIViewController, respectively.

It works just like UIView's layout subviews, and it's meant to do fine adjustments to the subviews of your hierarchy.

And that includes child content views, as well.

So when your Presentation Controller got that message that the presentedViewController needs to have a different size, you would change that presentedViewController's size in containerViewWillLayoutSubviews.

So now that we understand how all the messaging flows through the controller hierarchy, let's take a look at the demo that shows how we do adaptivity to our demo app, and then it also shows how to use multiple Presentation Controllers to show to display the same view controller content.

So we're going to go back to the same demo application we were looking at earlier my photo management application.

Using the same API that Jim talked about for UI popover Presentation Controller adapting, we can adapt our custom view controller too.

As you remember, we have this side bar.

But when we transition to a compact-width environment, what we'd really like to have is just a full-screen presentation.

Here, we'll change the width to 320 and the size class to compact.

And check it out: we get a full-screen presentation.

This is using that same adaptive presentation style at adaptivity API on Presentation Controller that we showed you in popover Presentation Controller.

But what's really cool is that we can still use our custom animator object.

So you'll notice that when we dismiss the view controller by tapping the Save button, we slide off from the right.

And when we present again, we slide in from the right.

This is exactly what we want.

And to show that it goes the other way, I'll change the size class back to regular, with the width of 768 points, and boom: it transitions perfectly and gets placed correctly.

Next, I'd like to show you something really cool.

Because Presentation Controllers are not coupled to their presentedViewControllers, we can switch out a Presentation Controller that's usedfor a view controller with zero changes to the presentedViewController.

I'm going to tap this little switch in the corner, which turns on Cool mode.

This flips some internal state in my view controller to use a different transitioning delegate, which will provide a totally custom animator and totally custom chrome through its Presentation Controller.

So when I tap a photo, instead of that overlay side bar presentation, the view controller slides in from the middle, a beautiful leopard print appears from the side, and we get some totally custom chrome.

You'll notice some things about this custom presentation.

When we do the presentation, while the unicorn and the flower appear alongside the view controller animating in, the leopard print animates by itself.

This is because UIPresentationController can animate its chrome in a different animation block than that which is used for the view controller presentation.

So we can make that chrome respond just how we want.

By the way, this sample code, including Cool mode, is available on the Worldwide Developer's Conference website.

Just look for Look Inside.

Let's see how we implemented this totally custom Presentation Controller and switch the Presentation Controller we used for our overlay view controller.

Back in our root view controller, I showed you setting up our transitioning delegate like this.

We're going to need to augment this logic a little bit to provide our other Presentation Controller.

First, we'll check a new internal method that we've called presentationShouldBeAwesome.

And if this is true, will use a totally new transitioning delegate.

This transitioning delegate will provide a custom animator object to manage that scaling animation, and a custom Presentation Controller to manage the chrome that you saw earlier.

Otherwise if that value is not set to YES, we'll just use the other transition delegate that you saw earlier.

And then, setting this on the view controller will cause all of that machinery to be put in place when we go to present.

So to summarize what we talked about here today, there's only two points that we really need to take home with you.

First off, the UIPresentationController, UIKit ourselves are eating our own dog food and have really improved our own API for alerts, and for popovers, and for search.

No longer do you need to put their views into your hierarchy, if they could be best served by a presentation.

Additionally, with Presentation Controller representing the last piece in the puzzle for totally custom presentations, you can now build things that you never could before with custom chrome and custom animations.

And we encourage you to go make your own Cool mode.

We can't wait to see what types of totally custom presentations you're going to add to your application.

So if you have more information or questions, Jake Behrens, the guy in plaid down here, is our App Frameworks Evangelist.

He loves hearing from you guys.

Of course, there's documentations in the Apple Developer Forums.

More importantly, though, there are related sessions.

This is the last talk on UIViewController, What's New in View Controllers in iOS 8.

So all the sessions were earlier in the week.

I highly recommend that you check them out on the videos.

And that's it.

Enjoy the rest of your conference, and lets have a great [inaudible], guys.

[ Applause ]

原文地址:https://www.cnblogs.com/iosblogx/p/4695194.html