In this part we will see How we can customize push and pop animation of navigation controller and further more we will create real life reusable View using custom modal transition (Bottom Sheet)
In previous part we built custom presenting view controllers , you can build custom transitions to push and pop new view controllers.” as well. If you read previous part , you’ll find that custom navigation controller transitions feel quite similar to presenting view controllers.” It is highly recommended to read previous part
As shown in Gif we we are doing standard push and pop animation here
This is the only difference you can say between custom modal transition and Custom navigation transitions
- UIKit lets you customize navigation transitions via the delegate pattern in almost the same way you do for presenting view controllers.
You’ll make your
MasterViewControllerclass adopt the
UINavigationControllerDelegateprotocol and set it to be the delegate to your navigation controller. Each time you push a view controller onto the navigation stack, the navigation controller will ask its delegate whether it should use the built-in transition or a custom one, as illustrated below:” self.navigationController?.delegate = self
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
- When you push or pop a view controller, the navigation controller asks its delegate to provide an animation controller for that operation.
If you return
nilfrom that delegate method, the navigation controller will use the default transition. However, if you return an object, the navigation controller will use this instead as a custom transition animation controller. Yup — this sounds a lot like the previous chapter, doesn’t it?
The animation controller should adopt the same
UIViewControllerAnimatedTransitioningprotocol you worked with in the previous chapter. Once you provide an animation controller object (or animator), the navigation controller will call the following methods on it:
This step remains the same
- The animation controller should adopt the same
UIViewControllerAnimatedTransitioningprotocol you worked with in the previous blog. Once you provide an animation controller object (or animator), the navigation controller will call the following methods on it:
- First, the navigation controller calls
transitionDuration() to find out how long the transition will last; it then calls
animateTransition(), which is where your custom transition animation code will live.”
As shown in Figure 3 we are getting everything right
- po transitionContext.viewController(forKey: .from)! return ViewController instead if UINavigationController, the problem we face in previous blog, because of the change we did
- VC1 → Main View frame = (0 0; 428 926);
- VC2 → Main View frame = (0 0; 428 926);
we want that when user tap on VC1 View we push VC2 as fade in / out animation . If you want to learn this animation see this blog
As shown in Gif 2 , we push VC2 which is (SecondViewController) and customize its transition animation instead of stanndard and vice versa when pop. Few things to note
- Fade in/out animation we make this animation generic so no presenting and dismissal check
- Same in previous blog transitionContext.containerView.addSubview(toVC!.view) this is very important since toVC!.view) not always added in container view
- We are changing alpha of toView in animation blog , also we know in previous blog when push toView = SecondViewController and when pop toView = ViewController
When pushing and popping with parameter animated : false you will see no animation at all. It will not perform any transition animation
As you can see return nil in UINavigationControllerDelegate what it will do it will perform standard push and pop animation,
Bottom Sheet Using Custom Modal Transition
As shown in Gif2 , we will develop this very popular Bottom Sheet style animation using custom modal transition to practice further and it will be very helpful in your future project
As shown in Gif3 and Figure 7 code we used standard modal transition and it is not what we expect , we want our Bottom sheet take whole screen from scratch and make it transparent and then our white card view appear, so standard transition will not work we need to do some customization. For code
- We created
- created white card View programatically , giving it’s height to 500 and added constraint to anchor at the bottom and do some styling
Our objective is to create
BottomSheetController that when presented take whole screen
1. first and make presenting screen transparent and then present white Card View in an animated way from bottom to top .
2. Our second objective is to make
BottomSheetController independent of presenting view controller , weather your presenting view controller is in embedded in navigation of not having navigation,
As shown in Figure 8 we setup custom animation work , few things to note
- self.transitioningDelegate = self we added in
initmethod , previously we implement this is presenting view controller , consider our second objective , we want to make it independent of presenting View Controller
- Also we make
UIViewControllerAnimatedTransitioningto make it animator object itself, You should create separate class for that for the simplicity we are doing this
Note: An animator object is any object that adopts the
UIViewControllerAnimatedTransitioningprotocol. An animator object creates animations that execute over a fixed period of time. The key to an animator object is its
animateTransition:method, which you use to create the actual animations.
As shown in Figure 9 , we implemented present animation logic of Bottom Sheet. You can see the result in Gif4 . Few things to understand
- First we added BottomSheet main View to the container which is very important otherwise your animation will not work
- We set initial value of our animation, since bottomSheet main View start from clear and animate it’s clear to transparent with animation. Note: we access self.view since self is
- Also card view animate from Bottom to top with animation we set the start value of white card bottom from screen to same distance as height of screen and you can see in Figure 10, from where card view started , you can tweak this value as you want. You can learn in depth about transform property animation inn this blog where I explained using math and example
- In animation block we change card view position to original and also change the background color to transparent . This will happen with animated way in 0.44 seconds
- Finally and very important , in completion block we marked this animation as complete by calling completeTransition with true. You must call this method after your animations have completed to notify the system that the transition animation is done. The parameter you pass must indicate whether the animations completed successfully.he best place to call this method is in the completion block of your animations. The default implementation of this method calls the animator object’s animationEnded(_:) method to give it a chance to perform any last minute cleanup. Calling the
completeTransition:method at the end of your animations is required. UIKit does not end the transition process, and thereby return control to your app, until you call that method.
As shown in Figure 11, you can self.view but as per apple
When setting up custom animations, always use the objects and data in the transitioning context object rather than any cached information you manage yourself. Transitions can happen in a variety of conditions, some of which might change the animation parameters. The transitioning context object is guaranteed to have the correct information you need to perform the animations, whereas your cached information might be stale by the time your animator’s methods are called.
Now comment out this line as shown in Figure 12 and tap on button you will see no animation will occur and you only see presenting view controller only , Also UI became unresponsive and you can’t do anything, your question would be
- transitionContext.completeTransition(true) , why UI still unresponsive, the answer is you provide true which means the transition has done successfully and bottom sheet appear but bottom sheet not appear because you did’t add
containerViewwhich performs actual animation
When the transition between the two view controllers begins, the existing view is added to a transition container view and the new view controller’s view is created but not yet visible. Therefore your task is to add the new view to the transition container within
animateTransition(using:), “animate in” its appearance and “animate out” the old view if required. By default, the old view is removed from the transition container when the transition animation is done.
Now setting completeTransition(false) if you didn’t get proper view , what it will do it will not show BottomSheetController but UI will not stuck .
As shown in Figure 14 and 15 we created a dismiss transition , few things to note
- we only added transitionContext.containerView.addSubview(toView) when presenting . Remember when present
toViewalways added to
containerViewotherwise animation will not work, but when dismiss it is not necessary , and in our case our presented view controller will take whole screen until animation will complete so it safe not to add toview when dismiss (but Note when present always add toView). Also please note when pushing and poping you always add toView weather it is pushing or popping because in pushing previous view controller content replace with the new one. In the case of modal presentation the content is added above presenting view controller so you have some flexibility not to add
toViewwhen dismiss )
- Then we reverse starting and end values as we normally do and everything work as expected
- Note : if you remove navigation controller of presenting view controller this will also work because we didn’t do anything on presenting View controller
In Gif 2 we push and pop I only added toView when pushing and when we dismiss you can see black screen appear , so in short when pushing and popping always add toView to the container view
In previous part we work on modal animation , here try to add ToView when present and you can see since it present as modal
- When present we should add toView in container otherwise animation will not work at all
- Second we only add
toViewwhen present so in dismiss it recover since in modal new content added above old content , but we get black within animation duration it because container view is used in animation until animation finishes so when present animation finishes, the presenting view controller remove from container view and when dismiss we didnn’t add toView so in while animation container don’t find any toView so it present black. and we know that container view is responsible for all animation after animation finish old content restore and we get previous screen so user not block with this . In Bottom sheet our bottom sheet appear until animation finishes so we skip to add toView to the container
as shown in Figure 17 we override loadView and after adding our loadview animation will not work since it is getting frame 0 , i didn’t able to find the reason , if anyone know let comment out and give reason
In next blog we will see how to perform subView animation while doing custom transition
iOS Animation Tutorial: Custom View Controller Presentation Transitions
Learn how to create custom view controller presentation transitions and spice up the navigation of your iOS apps…