Fork me on GitHub

Blur Backgrounds and Custom Modal Transitions

Sergio Campamá - 19 Jan 2014



Welcome back! In this post we are going to learn 2 tricks for iOS 7 app development. The first trick lets you present a view that blurs the views behind it, very iOS 7 style. The second one is how to make custom animations for modal view controller presentations and dismissals. I haven't tested it yet, but I'm sure this concepts apply also to push animations as well.

I learnt the basics of this tutorial on CodeSchool's Core iOS7 course, be sure to check it out! It's a great course to get you up to speed in everything new in iOS7.

This post is accompanied by an iOS Demo app, which you can download/fork/check out/comment here

Blurred Backgrounds

Ok, so there are 2 types of blurred backgrounds:

  1. Static Blur
  2. Dynamic Blur

The static approach consists of rendering the views behind the view for which we want the blurred background. That render is saved to an UIImage and a blur is applied with the UIImage+ImageEffects categories provided by Apple. Finally, the blurred image is set as the background to the view.

The main problem with this approach is that if the background views change, or the view is moved, the blurred background won't update dynamically, which will look awkward.

The dynamic approach

This approach is a very cool trick, in which we utilize the dynamic blur effects already implemented in the UIToolbar and UINavigationBar in iOS7. The trick consists of creating a UINavigationBar, setting its frame to the bounds of the bounds of the view we want to give the blurred background, and then inserting the toolbar's layer as the first layer in the view's layer hierarchy. Is your mind blown now?

  - (void)viewDidLoad
  {
      [super viewDidLoad];
      
      self.view.backgroundColor = [UIColor clearColor];
      self.lenderBar = [[UINavigationBar alloc] initWithFrame:self.view.bounds];
      self.lenderBar.barStyle = UIBarStyleDefault;
      [self.view.layer insertSublayer:self.lenderBar.layer atIndex:0];
  }


You can see how the background is blurred in the modal view. In the demo you'll see that it's also dynamic.

There are some couple of gotchas that are needed in order for this to work with orientation changes, which you can find in the demo's source code.

Custom Modal Transitions

So, in order to understand how custom transitions work, we need to understand the way iOS 7 conceptualizes the different components of a custom transition. There are 2 important concepts:

  1. Transitioning Delegate
  2. Animation Controller

Transitioning Delegate

The transitioning delegate is the element in charge of providing the correct controllers for the transition animations. This is a property of the modal view controller to be presented.

  - (IBAction)showModal:(id)sender
  {
    ModalViewController *controller = [ModalViewController new];
    controller.modalPresentationStyle = UIModalPresentationCustom; // Needed for custom animations to work
    controller.transitioningDelegate = self; //Conforms to the UIViewControllerTransitioningDelegate protocol
  }

The UIViewControllerTransitioningDelegate protocol specifies 3 methods:

  1. - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
  2. - (id)animationControllerForDismissedController:(UIViewController *)dismissed
  3. - (id)interactionControllerForPresentation:(id)animator
  4. - (id)interactionControllerForDismissal:(id)animator

I know, those are some very big method names, but they're not that scary. The first one returns an animation controller in charge of the presentation of the modal view controller, while the second one delivers the animation controller that deals with the dismissal of the view controller. The third and fourth methods return an interaction controller, which will be a controller for the animation controllers in situations where you want to let the user interact with the presentation and dismissal transitions.

Animation Controller

The animation controller is the element which will implement the animations for the view. It has to conform to the UIViewControllerAnimatedTransitioning protocol, which defines 2 methods that need to be implemented:

  1. - (NSTimeInterval)transitionDuration:(id)transitionContext
  2. - (void)animateTransition:(id)transitionContext

The first method returns the duration of the transition, which I've seen many times defined to just return 1.0. The second method is where the animation controller implements the animation per se.

The transitionContext is where you will get all the necesary elements to complete the animations. For example, for a presenting animation, this context provides you with the presenting view controller, aliased as fromViewController and the modal view controller, aliased as toViewController.

The transitionContext also provides you with a containerView, which is the view where the animations will take place. This view already contains the fromViewController's view, and the animation controller is expected to add the toViewController's view into the container view's hierarchy. Finally, to mark the transition as complete, you have to tell the transitionContext.

There are many approaches that can be used to implement the animations, some of which are implemented in the demo. We can define the animations using UIView's animations with block methods, as shown in the following example.

  - (void)animateTransition:(id)transitionContext
  {
      UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
      UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
      
      CGRect fromVCFrame = [transitionContext initialFrameForViewController:fromVC];
      
      CGRect finalFrame = CGRectMake(20, 20, CGRectGetWidth(fromVCFrame) - 40, CGRectGetHeight(fromVCFrame) - 40);
      
      CGRect initialFrame = [self initialFrameFromFinalFrame:finalFrame inTransitionContext:transitionContext];
      
      toVC.view.frame = initialFrame;
      [[transitionContext containerView] addSubview:toVC.view];
      
      [UIView animateWithDuration:[self transitionDuration:transitionContext]
                            delay:0.0f
           usingSpringWithDamping:0.5f
            initialSpringVelocity:0.6f
                          options:UIViewAnimationOptionCurveEaseInOut
                       animations:^{
                           toVC.view.frame = finalFrame;
                       }
                       completion:^(BOOL finished) {
                           [transitionContext completeTransition:YES];
                       }];
  }

Another way of animating the views is using the new UIDynamicAnimator and company of UIDynamicBehaviours, which are a really cool feature to animate views with familiar effects like UIGravityBehaviour.

Well, I think that covers the concepts necessary to understand the demo and learn more from it. The demo also contains the implementation of the interaction controller for dismissal mechanic, which allows the user to control the pace of the animation using his fingers. Please leave a comment if you have any questions!


comments powered by Disqus