Bummer! This is just a preview. You need to be signed in with a Pro account to view the entire video.
Start a free Basic trial
to watch this video
This workshop focuses on creating a custom transition for a modal view controller’s presentation and dismissal. Instead of relying on Apple’s standard modal transitions, such as the slide-in from the bottom of the screen, cross-dissolve, flip, etc. we will create our own custom transition.
-
0:00
[MUSIC].
-
0:03
[SOUND] Starting in iOS7.
-
0:06
Apple added the ability to create custom transitions between view controllers.
-
0:11
Today we're going to focus on creating a custom transition for
-
0:14
a modal view controller's presentation and dismissal.
-
0:18
So instead of relying on Apple's standard modal transitions,
-
0:21
such as the slide in from the bottom of the screen, cross dissolve,
-
0:25
flip, etc., we'll create our own custom transition.
-
0:28
[SOUND] For our workshop demo, we're going to build a simplified version of a photos
-
0:32
app, where users tap on an image thumbnail to view the image in a full screen modal.
-
0:37
We'll use a custom view controller transition to launch and
-
0:40
dismiss a view controller.
-
0:42
So let's get started.
-
0:52
Let's create a new single view project in x code.
-
0:56
We'll call it transitions demo.
-
1:07
We're going to add an image into the project,
-
1:09
which we'll be using in our views.
-
1:23
In the viewercontrol.m file infuted load we'll create a button that
-
1:27
displays an image.
-
1:44
[NOISE] So UIButton button equals UIButton buttonWithType: UIButtonTypeCustom,
-
1:50
We'll add target self with selector present modal.
-
1:54
[SOUND].
-
2:03
Then, we'll set the button's image to the one we added to the project.
-
2:20
We'll set translatesAutoresizingMaskIntoConstraints
-
2:27
to no, then add it as a subview of self.view.
-
2:32
Then, we'll add some basic constraints,
-
2:41
making it 150 point square
-
2:46
with 30 points of top and
-
2:51
right padding.
-
2:54
[SOUND] The vertical constraints will just copy
-
3:01
the horizontal constraints [SOUND] and
-
3:07
will change h to v and update the string.
-
3:14
[SOUND] So we'll have a square button with our image on it,
-
3:17
150 point square in the top right corner.
-
3:20
Next, let's create that present modal method.
-
3:30
In it, we'll be presenting our modal, so we'll need to create that view now.
-
3:36
In X code, we'll go to File, New File, and select Coco touch class, and then name
-
3:42
our file custom modal view controller, a subclass of UI view controller.
-
3:48
Hit next, then create, and our class is added to our project.
-
3:52
Let's import CustomModalViewController.h at the top of ViewController.m.
-
4:00
[SOUND] And then down in present modal,
-
4:07
we'll create a new instance
-
4:12
of the view controller.
-
4:16
[SOUND] Then we'll call presentViewController,
-
4:20
animated, yes, with an empty completion block.
-
4:24
Next, let's open CustomModalViewController.m and
-
4:27
under viewDidLoad let's add our full screen image and a close button.
-
4:32
To add some visual separation, let's first set self.views background color to black..
-
4:37
[SOUND] Next, let's build our close button.
-
4:45
We'll create it with type custom.
-
4:47
[NOISE] Then, we'll set
-
4:51
translate auto resizing
-
4:56
mass into constraints to know.
-
5:03
We're just going to keep this simple.
-
5:04
So the close button will just be the letter x.
-
5:07
We'll just set its title to the string, x.
-
5:13
Then we'll set its title label font to system font of size
-
5:16
twenty-four.
-
5:23
We'll set its title color to light-gray color.
-
5:33
Then add target self, with action close button pressed.
-
5:37
[SOUND] Finally, we'll add the button
-
5:43
as a subview of self dot view.
-
5:49
We want to position this button in the top right corner of our view.
-
5:53
So we'll create some auto layout that makes it 40 point square
-
5:57
with 10 points padding on the right, and 22 points padding above to account for
-
6:02
the status bar.
-
6:03
[SOUND].
-
6:40
Next we'll create our full-screen image view.
-
6:51
We'll create our instance, UI image view image view equals UI image view new.
-
6:57
Set it's content mode to fit.
-
6:59
Set translates auto resizing mask into constraints to no.
-
7:03
Set the image to our mabelFlip image.
-
7:06
[SOUND] Then, add it as
-
7:11
a subview of self.view.
-
7:17
[SOUND] Then, we'll setup imageView's constraints pinning it to the edges of its
-
7:21
super view, which is self.view.
-
7:40
Next we'll create that close button pressed method.
-
7:43
[SOUND] Inside it, we'll call self
-
7:49
dismiss view controller animated,
-
7:55
yes, with completion nill.
-
8:00
Now, lets launch the app, we can see our 150 by 150 point button,
-
8:04
containing our image.
-
8:11
If we tap it, we see our modal with the full screen image enclose button
-
8:15
in the tope right corner.
-
8:16
Tapping that close button dismisses our modal.
-
8:19
Great.
-
8:20
Of course we don't have any custom transitions yet.
-
8:22
We didn't specify anything for the modal presentation.
-
8:25
So it's defaulting to the slide up from bottom animation you're probably
-
8:29
familiar with.
-
8:30
Back in viewController.m, in our presentModal method, we're going to set
-
8:35
the modal presentation style on the controller to UIModalPresentationCustom.
-
8:44
If we click on UI modal presentation custom and bring up the quick help in
-
8:48
the utility sidebar in X code, we can see a quick description of this value.
-
8:53
If we tap on UIViewController class reference,
-
8:56
the documentation gives us a little more information.
-
9:00
It explains that we also need to set the transitioning
-
9:03
delegate on the view controller, and we have this
-
9:05
UI view controller transitioning delegate protocol to conform to.
-
9:09
So let's also set that transitioning delegate to self on the modal.
-
9:13
[SOUND] And up in our private
-
9:19
interface we'll add
-
9:24
the protocol UI view controller
-
9:31
transition delegate.
-
9:37
[SOUND] If we command on this protocol we can see that it contains several optional
-
9:41
methods.
-
9:42
We're going to grab two of these, the animationControllerForPresentedController
-
9:46
method and the
-
9:47
animationControllerForDismissedController method.
-
10:06
We'll copy these into our view controller's implementation, and
-
10:10
in both we'll return self.
-
10:12
What we're doing here is telling the modal that this view controller is going to be
-
10:16
its transitioning delegate.
-
10:18
That's step one.
-
10:19
Then we're also saying that when it wants an animation controller for
-
10:23
presenting or dismissing the modal Then this view controller will also be that.
-
10:27
You'll notice that we're getting warnings on the return self-line
-
10:30
of each of these delicate methods.
-
10:32
They're expecting the object to subscribe to another protocol,
-
10:35
UI View controller animated transitioning.
-
10:39
Which our view controller class isn't subscribed to yet.
-
10:42
So let’s add that to our private interface above.
-
10:46
Now if we command click into that protocol's implementation
-
10:49
we can see the methods it defines.
-
10:51
We have two required methods and one that is optional.
-
10:55
We'll just copy the two required ones into our view controller's implementation.
-
11:13
For transition duration we'll just return 0.5.
-
11:17
Animate transition is going to be where we define the custom transition itself first,
-
11:24
we're going to want to keep a reference to the current transition context,
-
11:31
so lets add that as a property in the private interface.
-
11:37
[SOUND] In animate transition, we'll set self dot transition context to
-
11:43
the transition context that gets passed into this method.
-
11:58
Now we're going to make use of this transition context object.
-
12:02
If we command click into the UI view controller context transitioning protocol,
-
12:07
we'll see many methods we can call on this transition context object.
-
12:11
We'll just be using this view for key method.
-
12:16
[SOUND] You'll notice this is IOS eight only.
-
12:19
If you need to support IOS seven, you'll want to instead use the similar view
-
12:23
controller for key methods, then access their views.
-
12:27
Back in the animate transition method, we'll use this method with two keys.
-
12:31
UI transitionContext From View key.
-
12:45
And UI transitionContext to view key.
-
12:55
So from view equals transitionContext view for
-
12:57
key UI transition context from view key, and
-
13:01
to view will equal transition context view for key UITransitionContextToViewKey.
-
13:07
We now have a reference to the UI view that presented the modal, and
-
13:10
the view that is being presented.
-
13:12
Our animation code is going to animate our modal view from the buttons frame
-
13:17
to full screen.
-
13:18
To help with this, we'll create two frame properties in our private interface.
-
13:22
ModalCollapsedframe [NOISE] and
-
13:28
modalExpandedframe.
-
13:32
We'll also create a property for our button,
-
13:36
which is what we'll use to create the collapsed frame.
-
13:41
[SOUND] In animate transition,
-
13:44
we'll set the modalCollapsedFrame to the buttons frame.
-
13:57
Then we'll set the modalExpandedFrame to transition context containerview.bounds.
-
14:13
This container view for the transitionContext is the view that acts as
-
14:17
the super view for the views involved in this transition next we need to
-
14:21
discuss an interesting aspect of these custom transitions.
-
14:24
If you're presenting, the to view is the modal and
-
14:28
the from view is the view that presented it.
-
14:32
If you're dismissing, they're the opposite.
-
14:35
To view Is the presenter, and from view is the modal.
-
14:39
It makes sense if you think about it, but
-
14:41
it means that we need to be able to check which is which.
-
14:44
Since we're setting our view controller as the animation controller for
-
14:47
both presented controller and dismissed controller,
-
14:51
this animate transition method gets called in both cases.
-
14:55
So let's create a BOOL property in our private interface, called isPresenting.
-
15:01
Now in present modal, let's set is presenting to yes,
-
15:05
right before present view controller.
-
15:08
Then set it back to no, in the completion block.
-
15:15
Now, back in our animate transition method,
-
15:18
we'll declare a UI view called modal view and a CG rect destination frame.
-
15:36
We'll set these in a minute.
-
15:38
Next, we'll create an if statement.
-
15:41
If self isPresenting, modalView will equal toView, and
-
15:45
destination frame will equal modal expanded frame.
-
15:52
Else, modal view will equal fromView, and destinationFrame,
-
15:56
will equal the modalCollapsedFrame.
-
16:01
Now, if we're presenting, there's something we’re expected to do, and
-
16:05
that's add the modal to the transition context container view.
-
16:08
[NOISE] We don't actually have
-
16:16
to ever remove this.
-
16:21
The animator will do that for us, but we do have to remember this when presenting.
-
16:25
Otherwise, no modalView will appear.
-
16:28
Also, if we're presenting, we want to first start the modal view
-
16:32
at the frame of the button so that it animates from that framed to full screen.
-
16:37
So, we'll set it's frame to the collapsed frame,
-
16:39
and then call layout if needed on the view.
-
16:43
Now, for the actual animation.
-
16:45
Let's create a new method.
-
16:47
[SOUND] We'll call it animate with modal view passing in a UI
-
16:52
view destination frame passing in the destination frame.
-
17:11
In this method, we'll create our animate with duration call and
-
17:15
I'm going to use the spring with damping variation with some values I like.
-
17:53
And you'll notice I'm using the transition duration method,
-
17:56
passing in our transition context property.
-
17:58
Although in our case, the method really doesn't do anything with it.
-
18:02
Inside the animation block, we'll set the views frame to our destination frame and
-
18:07
call layout if needed on it.
-
18:08
[SOUND] In the completion block, we'll call
-
18:13
complete transition on the transition context.
-
18:18
We'll pass in yes.
-
18:20
This call tells the transition context that we're done transitioning, so
-
18:25
at the bottom of our animate transition method
-
18:27
let's call this new animation method.
-
18:29
We'll call self animateWithModalView, modalView destinationFrame,
-
18:34
destinationFrame.
-
18:36
One final thing I forgot to do was set our button property,
-
18:39
self dot button, to the button we created.
-
18:41
I'll do that now.
-
18:42
[SOUND] So now, if we launch the app, we can see that tapping
-
18:48
the button gives us the desired modal animation and
-
18:53
tapping the close button animates us back to the button's frame.
-
18:59
Great.
-
19:00
You'll leave a notice that we didn't do anything special in the code to dismiss
-
19:03
the model.
-
19:04
We just called the standard dismiss modal view controller method.
-
19:09
The modal's transitioning delegate is simply called and it behaves a specified.
-
19:14
And since our modal's layout was done with auto layout
-
19:16
if you animate smoothly through the transition, positioning elements properly.
-
19:21
The image view is pinned to the edges of its superview, which at the beginning of
-
19:25
the transition are in the same position as the view controllers button frame.
-
19:29
As it animates up to full screen, the image view and
-
19:32
the close button on the top right position as expected.
-
19:35
Now, wouldn't it be cool if we could pinch to dismiss this modal?
-
19:40
And wouldn't it be cool if the animation would track our finger through
-
19:42
the gesture?
-
19:44
To do this we're going to create an interactor object.
-
19:47
We'll go to file, new file Then select coco touch class and we'll name it
-
19:52
interactor which will be a subclass of UI percent driven interactive transition.
-
19:58
This is the class Apple has provided for us to subclass and manage a transition
-
20:02
that we can actually control at every percentage step of the way.
-
20:06
Click Next, then create.
-
20:08
[NOISE] If we go to the files header and command-click on the super class,
-
20:14
we'll see a few properties and then three methods at the bottom.
-
20:20
Let's copy these into our files implementation.
-
20:22
[NOISE] So we have updateInteractiveTransition,
-
20:27
cancelInteractiveTransition and
-
20:31
finishInteractiveTransition now,
-
20:35
we're going to move all of our transitioning delegate and
-
20:41
animated transitioning protocol methods in our view
-
20:47
controller's implementation into this interacter's implementation.
-
20:55
We'll also move our animate with modal view method.
-
21:10
After we cut and paste, you'll see we need to bring over several properties too.
-
21:15
So we'll move these into our interacters interface.
-
21:18
We'll put the frames and the BOOLs in the public interface, and
-
21:21
the transition context in the private interface.
-
21:24
[NOISE] We don't actually
-
21:30
have a private interface
-
21:37
generated for us yet.
-
21:43
So we'll create one at the top of the dot M file.
-
21:47
We also need to bring over the protocol definitions.
-
21:50
We'll put these in the public interface.
-
21:54
[NOISE] In our view controller dot M file lets create an interacter property.
-
22:02
We'll first need to include its header,
-
22:09
then create the property.
-
22:13
[NOISE] In view did load,
-
22:17
we'll create the interactor.
-
22:32
Now, under presentModal,
-
22:33
we'll update the transitioning delegate on the modal, to self.interactor.
-
22:38
We also need to update our isPresenting bool,
-
22:41
since it's now a property on the interactor.
-
22:45
We still have en error in our interactor.m.
-
22:48
In animate transition we don't have access to the button property anymore, so
-
22:52
we'll need to remove this line.
-
22:54
[NOISE] We'll need to get this frame elsewhere.
-
22:59
Back in ViewController.m, in presentModal, we'll set the modalCollapsedFrame
-
23:04
on the interactor to the button's frame right before presentation.
-
23:08
[NOISE] Above this method,
-
23:12
I'm going to override view did layout subviews.
-
23:20
We'll first call super in it.
-
23:24
What we want to do is update the modal collapsed frame.
-
23:27
To the button frame, whenever the view may change.
-
23:31
So we'll check to make sure the interactor and button both exist, and
-
23:35
if so, we'll update this frame.
-
23:38
For our testing, this will get hit after the view rotates and
-
23:42
the button frame may be different than before.
-
23:45
Now if we run the app, we'll see that it’s working just as before.
-
23:50
Our refactor hasn't broken anything.
-
23:51
Good.
-
23:52
Let's go back to our interactor.h file and
-
23:55
Cmd+click on the UI view controller transitioning delegate protocol.
-
23:59
[NOISE] We want to copy the two interaction controller methods and
-
24:06
paste them into our interactor's implementation.
-
24:33
We'll return self in both of these.
-
24:35
You'll notice that again we have a protocol that our class needs
-
24:39
to subscribe to.
-
24:40
UIViewControllerInteractiveTransitioning.
-
24:44
If we Cmd+click into that,
-
24:46
we'll see that it has one methods start interactive transition.
-
24:50
We'll copy and paste that into our implementation since we have update,
-
24:54
cancel and finish interactive transition methods that we're overriding in
-
24:58
this class, we'll put it right above those.
-
25:04
There's one more thing we need to do with these interaction controller methods.
-
25:08
If we just returned self all the time we're essentially telling the custom
-
25:12
transition that we always want it to be an interactive transition.
-
25:16
We have to check to see whether we are doing a gesture based interactive
-
25:19
transition or the regular button press transition
-
25:23
which means we just want our standard custom animated transition to get called.
-
25:26
So we'll add a property to our public interface, a bool called isInteractive.
-
25:32
[SOUND] We'll set this to yes when we're
-
25:37
starting a gesture based transition.
-
25:42
Back in the implementation, we'll add a ternary operator, and
-
25:46
if we're interactive, return self, otherwise, return nil.
-
25:50
[SOUND] Next, let's flesh out
-
25:55
our interactive transition.
-
26:00
Under start interactive transition,
-
26:02
we'll save the transition context passed in, setting it to our property.
-
26:07
And we'll set the modal expanded frame to the transition context container view's
-
26:12
bounds.
-
26:15
Inside update interactive transition, we're going to write the code that
-
26:18
collapses the modal, based on percent complete.
-
26:22
This is where you're free to do something creative.
-
26:25
What we'll be doing is generating a frame that scales down from full screen
-
26:29
to the presenting buttons frame, just like the regular animated transition.
-
26:33
Percent complete will range from 0 to 1.
-
26:36
In a few moments,
-
26:37
we'll write a pinch gesture that passes its scale into this method.
-
26:41
We know that the pinch will start at a scale of one,
-
26:44
then reduce down toward zero as the fingers come together.
-
26:49
Whether your internal math here goes from zero to one or one to zero is up to you.
-
26:54
To keep things simple, we'll be passing in the pinch's scale,
-
26:58
expecting a transition from zero to one.
-
27:01
To keep things simple, we be passing in a pinch of scale,
-
27:04
expecting a transition of zero to one.
-
27:07
The first thing we'll do is get a delta or difference value for the origin x,
-
27:12
origin y, width, and height values of our expanded and collapsed frames.
-
27:18
We'll do this by subtracting the collapsed destination value
-
27:21
from the expanded starting value.
-
27:24
So for the x origin delta.
-
27:26
Will be self dot modal expanded frame dot original dot x minus self dot modal
-
27:31
dot collapsed
-
27:37
frame dot x.
-
27:44
[SOUND] The why origin delta will be the same.
-
27:48
The modal expanded y minus the collapsed y.
-
27:51
[SOUND] The x width
-
27:57
delta will be
-
28:02
the expanded
-
28:07
width minus
-
28:11
the collapsed width.
-
28:36
And the y height delta will be the expanded height minus the collapsed
-
28:40
height.
-
28:41
Next, we'll create a transition value for each of these four parameters,
-
28:45
by starting with the collapsed frames value, then adding the calculated delta
-
28:50
multiplied by our current percent complete.
-
28:53
In other words, we'll be trying to figure out
-
28:56
where should our modals frame be at this percent in the transition?
-
29:00
Starting with the collapsed frame's values,
-
29:02
we add on a percentage of the difference between the expanded and collapsed frames.
-
29:07
[NOISE] So the transition x will
-
29:12
be the modal collapsed frame origin x plus.
-
29:21
The delta for the x times percent complete.
-
29:25
And the transition y will be the same with the y value.
-
29:27
And again, the transition width and height will be
-
29:32
the collapsed values adding their delta multiplied by percent complete.
-
29:37
[SOUND] In copying and pasting,
-
29:42
be sure that your values are correct.
-
29:48
Next, we need to get a reference to our modal view from the transition context.
-
29:53
Since we're only doing the gesture on dismissal,
-
29:56
we know it's going to be the from view So we'll call
-
29:59
self.transitionContext viewForKey UI transition context from view key.
-
30:04
Next, we'll set the from views frame to our transition origin x and
-
30:09
origin y, transition width, and transition height values.
-
30:22
Now, under finish interactive transition and cancel interactive transition,
-
30:27
we're basically going to call our animate with modal view method we created,
-
30:31
either dismissing down to the button frame, or cancelling the dismissal, and
-
30:35
animating back to full screen.
-
30:38
In both methods, we'll copy and paste in the from view line from the update
-
30:42
interactive transition, where we get it from the transition context.
-
30:46
We now need to make a small update to our animate with modal view method.
-
30:50
When we call it from cancel interactive transition,
-
30:53
we don't want to call complete transition yes in the animation completion block.
-
30:57
We want to say no instead so let's add didComplete as a bool variable
-
31:03
that gets passed into the method.
-
31:11
Then when we call complete transition, we'll just pass in didComplete.
-
31:16
This means we'll need to update the method call at the end of animateTransition,
-
31:19
passing in yes for didComplete in this case.
-
31:22
Then in finishInteractiveTransition we'll call animateWithModalView,
-
31:26
passing in the collapsed frame for the destination frame and yes for didComplete.
-
31:37
And in cancelInteractiveTransition we'll call the same method to pass in
-
31:42
the expanded frame for the destination frame, and no for did complete.
-
31:52
There's an optional method under UI view controller animated transitioning
-
31:56
named animation ended.
-
31:57
We'll add this method to our interacter and use it to clean up a bit.
-
32:01
We'll set our isInteractive and
-
32:09
isPresenting BOOL
-
32:14
values to no whether or not
-
32:21
the transitionCompleted
-
32:28
value is yes or no.
-
32:34
This way, we're in a good default position for whatever the user may do next.
-
32:38
Now, we'll go to our custom modal view controllers implementation and
-
32:42
set up the pinch gesture along with some other details.
-
32:45
For the pinch gesture to talk to our interactor, we'll need to have a way for
-
32:48
them to communicate.
-
32:50
Let's create an init method that passes in an interactor object.
-
32:54
We'll first need to import our interactor header file.
-
32:57
Then we'll add a property for the interactor in our private interface.
-
33:09
Then we'll create our new init method,
-
33:11
setting our interactor property to the one passed in.
-
33:20
So we'll write, instance type,
-
33:24
init with interactor, interactor,
-
33:29
if self equals super init, return self.
-
33:34
And inside the if statement, our interactor property equals interactor.
-
33:39
We'll also going to expose this init method in the header.
-
33:42
[SOUND] And we'll need to declare
-
33:47
the interactor class in the header as well.
-
33:59
Now, back in the dot m file, at the end of our view did load method,
-
34:03
let's set up a UIPinchGestureRecognizer, targeting self with the action
-
34:08
set to user did pinch, and then add the gesture recognizer to self.view.
-
34:26
So we'll write UIPinchGestureRecognizer PinchRecognizer
-
34:31
equals UIPinchGestureRecognizer alloc initWithTarget self action
-
34:37
selector userDidPinch Then self.view addGestureRecognizer pinchRecognizer.
-
34:44
Next we'll create this userDidPinch method.
-
34:47
[SOUND] Inside the method, we'll stem
-
34:52
out our three basic states began,
-
34:57
changed, and ended or canceled.
-
35:33
Inside began, we'll tell our interactor instance that is interactive is yes,
-
35:39
and that is presenting is no.
-
35:41
Since we're only doing an interactive dismissal,
-
35:44
we know that we are not presenting here.
-
35:57
Next we call dismissed view controller,
-
35:59
just as you would with the normal modal dismissal.
-
36:01
Inside changed, we'll first check that
-
36:07
the recognizer scaled is less than or equal to one.
-
36:14
In other words, we only want pinches that get smaller,
-
36:17
not pinches that might be a zooming in gesture.
-
36:20
Then, we'll call update interactive transition passing in the recognizers
-
36:24
scale value.
-
36:39
So we'll write, if recognizer scale is less than or equal to 1,
-
36:43
call self.interactor, update interactive transition, passing in recognizer.scale.
-
36:50
In ended or canceled, we'll check if the recognizer scale is beyond a certain
-
36:54
arbitrary point, which we’ll set to be 0.5, or half way.
-
37:00
If it's less than that value,
-
37:01
we'll call finish interactive transition on our interactor.
-
37:05
Otherwise, we'll call cancel interactive transition.
-
37:09
So we'll write another ternary operator here to call one of these two methods.
-
37:14
So we'll write recognizer.scale less than 0.5, if so
-
37:18
self.interactor Finish interactor transition.
-
37:21
Otherwise, self.interactor cancel interactor transition.
-
37:25
If you remember, these methods inside the interactor
-
37:28
animate the modal to it's expanded or collapsed frame.
-
37:32
Finally, we'll need to go back to our viewcontroller.m file and
-
37:35
update the custom modal view controllers instantiation with our new method
-
37:39
that passes in the interactor.
-
37:45
Now, if we build and run, we'll get to try out our new pinch gesture based dismissal.
-
37:50
If we launch the modal, then pinch to dismiss, and
-
37:53
when we've released the pinch beyond halfway, it closes.
-
37:57
If we pinch and release before halfway, it bounces back to full screen, great!
-
38:06
One final thing to show is that if we start in portrait, launch the modal,
-
38:10
then rotate to landscape, then start our dismissal,
-
38:14
it gets the proper collapsed frame for its final position.
-
38:18
This is because of our frame update code in view controllers viewdid
-
38:21
layout subviews.
-
38:23
So even though the button's position has changed,
-
38:25
we still animate out to the proper frame.
-
38:29
Great, that's it for this workshop.
-
38:32
I hope you've acquired some useful tools to help you build you own,
-
38:34
cool view transitions.
-
38:36
Thanks for watching.
You need to sign up for Treehouse in order to download course files.
Sign up