Home iOS & Swift Tutorials

UIPresentationController Tutorial: Getting Started

Learn how to build custom view controller transitions and presentations with this UIPresentationController tutorial.


  • Swift 5, iOS 13, Xcode 11
Update note: Ron Kliffer updated this tutorial for iOS 13, Xcode 11 and Swift 5. He also wrote the original.

View controller presentation has been an integral part of every iOS developer’s toolkit since the early days of iOS.

You’ve probably used present(_:animated:completion:) before but, if you’re like a lot of developers, you’ve stayed with the default transition styles shipped with iOS.

In this UIPresentationController tutorial you’ll learn how to present view controllers with custom transitions and custom presentation styles.

No longer will you be limited to full screen or popover presentations and the standard transition animations. You’ll start with some drab, lifeless view controller presentations and bring them to life.

By the time you finish, you’ll learn how to:

  1. Create a UIPresentationController subclass.
  2. Use a UIPresentationController for slick custom presentations. The presented view controller doesn’t even have to know it’s there.
  3. Reuse a UIPresentationController for various controllers, by tweaking presentation parameters.
  4. Make adaptive presentations that support any screen size your app might encounter.

Getting Started

With the 2020 summer games a year away, a client hires you to create an app that tallies the medal count for the competing nations.

While the functional requirements are pretty simple, your sponsor asked for a rather cool looking slide-in transition to present the list of games.

At first, you feel a bit of panic. But then you realize you do have transition-building tools at your fingertips. You even put down the paper bag!

Use the Download Materials button at the top or bottom of this tutorial to download the starter project.

Take a moment to familiarize yourself with the project and the following elements:

  • MainViewController.swift: The main controller of this project from which all presentations start. This will be the only existing file in the project that you’ll modify.
  • GamesTableViewController.swift: Displays a list of Games the user can select.
  • MedalCountViewController.swift: Displays the medal count for the selected sporting event.
  • GamesDataStore.swift: Represents the model layer in the project. It’s responsible for creating and storing model objects.

Before you start changing things around, build and run the app to see what it does. You’ll see the following screen:

App's landing page before any changes

First, tap Summer to bring up the summer menu, GamesTableViewController.

Summer menu

Notice the menu presentation is the default one, which is from the bottom. The client wants to see a sleek slide-in instead.

Next, tap London 2012 to dismiss the menu and return to the main screen. This time, you’ll see an updated logo.

London 2012

Finally, tap Medal Count to bring up MedalCountViewController for the 2012 games.

Medal count

As you see, this controller also uses the old bottom-up, default presentation. Tap the screen to dismiss it.

Now you’ve seen the app you’ll upgrade, it’s time to turn your attention to some core concepts and theory for UIPresentationController.

Core Concepts for iOS Transition

When you call present(_:animated:completion:), iOS does three things.

First, it instantiates a UIPresentationController. Second, it attaches the presented view controller to itself. Finally, it presents it using one of the built-in modal presentation styles.

You have the power to override this mechanism and provide your own UIPresentationController subclass for a custom presentation.

If you want to build sweet presentations in your apps, it’s mandatory to understand these key components:

  1. The presented view controller has a transitioning delegate that’s responsible for loading the UIPresentationController and the presentation and dismissal animation controllers. That delegate is an object that conforms to UIViewControllerTransitioningDelegate.
  2. A UIPresentationController subclass is an object that has many presentation-customizing methods. You’ll see some of these later in the tutorial.
  3. An animation controller object is responsible for the presentation and dismissal animations. It conforms to UIViewControllerAnimatedTransitioning. Note that some use cases warrant two controllers: one for presentation and one for dismissal.
  4. A presentation controller’s delegate tells the presentation controller what to do when its trait collection changes. For the sake of adaptivity, the delegate must be an object that conforms to UIAdaptivePresentationControllerDelegate.

That’s all you need to know before you dive in!

Creating the Transitioning Delegate

A transitioningDelegate inherits from NSObject and conforms to UIViewControllerTransitioningDelegate.

UIViewControllerTransitioningDelegate protocol, as its name hints, declares five optional methods for managing transitions.

You’ll work with three of these methods quite a bit in this tutorial.

Setting Up the Framework

Go to File ▸ New ▸ File…, choose iOS ▸ Source ▸ Cocoa Touch Class, and click Next. Set the name to SlideInPresentationManager, make it a subclass of NSObject and set the language to Swift.

Click Next and set the group to Presentation, then click Create.

Note: You declare SlideInPresentationManager to be an NSObject because transitioningDelegate of UIViewController must conform to NSObjectProtocol.

Open SlideInPresentationManager.swift and add the following extension:

// MARK: - UIViewControllerTransitioningDelegate
extension SlideInPresentationManager: UIViewControllerTransitioningDelegate {

Here, you make SlideInPresentationManager conform to UIViewControllerTransitioningDelegate.

In MainViewController you have buttons for both seasons: Summer on the left and Winter on the right. There’s also a Medal Count on the bottom.

To make the presentations fit each button’s context, you’ll add a direction property to SlideInPresentationManager. Later, you’ll pass this property to the presentation and animation controllers.

Add the following to the top of SlideInPresentationManager.swift:

enum PresentationDirection {
  case left
  case top
  case right
  case bottom

Here, you declare a simple enum to represent the presentation’s direction.

Next, add the following property to SlideInPresentationManager:

var direction: PresentationDirection = .left

Here, you’re adding a direction and giving it a default value of left.

To assign an instance of SlideInPresentationManager as the transitioningDelegate for every controller you present, open MainViewController.swift and add the following above dataStore definition:

lazy var slideInTransitioningDelegate = SlideInPresentationManager()

You might ask yourself why you’re adding this as a property on MainViewController. There are two reasons:

  1. transitioningDelegate is a weak property, so you must keep a strong reference to the delegate somewhere.
  2. You don’t want to keep this reference on the presented controller itself as you might want to reuse it on different presentation styles. Deciding the type of presentation to use is now the presenting controller’s task.

Next, locate prepare(for:sender:), and replace it with the following:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  if let controller = segue.destination as? GamesTableViewController {
    if segue.identifier == "SummerSegue" {
      controller.gamesArray = dataStore.allGames.summer

      slideInTransitioningDelegate.direction = .left
    } else if segue.identifier == "WinterSegue" {
      controller.gamesArray = dataStore.allGames.winter

      slideInTransitioningDelegate.direction = .right
    controller.delegate = self

    controller.transitioningDelegate = slideInTransitioningDelegate

    controller.modalPresentationStyle = .custom
  } else if let controller = segue.destination as? MedalCountViewController {
    controller.medalWinners = presentedGames?.medalWinners

    slideInTransitioningDelegate.direction = .bottom
    controller.transitioningDelegate = slideInTransitioningDelegate
    controller.modalPresentationStyle = .custom

Here’s a section-by-section explanation of what you’ve set up:

  1. Presentation direction of the summer games menu is .left.
  2. Presentation direction of the winter games menu is .right.
  3. The games controller’s transitioningDelegate is now the slideInTransitioningDelegate declared earlier.
  4. The modalPresentationStyle is .custom. This makes the presented controller expect a custom presentation instead of an iOS default presentation.
  5. Presentation direction of MedalCountViewController is now .bottom. The transitioningDelegate and modalPresentationStyle are set as you did in steps 3 and 4.

You’ve reached the end of the section and have set yourself up with the groundwork necessary for the next big thing coming at you: the UIPresentationController subclass.

Creating the UIPresentationController

Sit back and picture this for a moment: The presented controller will take up two-thirds of the screen and the remaining third will show as dimmed. To dismiss the controller, you just tap on the dimmed portion. Can you picture it?

Okay, clear your head and come back to the project. In this part, you’ll take care of three critical pieces: subclass, dimming view and customizing the transition.

Creating and Initializing a UIPresentationController Subclass

Go to File ▸ New ▸ File…, choose iOS ▸ Source ▸ Cocoa Touch Class and click Next. Set the name to SlideInPresentationController, make it a subclass of UIPresentationController and set the language to Swift.

Click Next and set the group to Presentation.

Click Create to make your new file and add the following inside the class definition in SlideInPresentationController.swift:

// MARK: - Properties
private var direction: PresentationDirection

init(presentedViewController: UIViewController,
     presenting presentingViewController: UIViewController?,
     direction: PresentationDirection) {
  self.direction = direction

  super.init(presentedViewController: presentedViewController,
             presenting: presentingViewController)

Here’s what this does:

  1. Declares direction to represent the direction of the presentation.
  2. Declares an initializer that accepts the presented and presenting view controllers, as well as the presentation direction.
  3. Calls the designated initializer for UIPresentationController.

Setting Up the Dimming View

As mentioned before, the presentation controller will have a dimmed background. Add the following to SlideInPresentationController, just above direction:

private var dimmingView: UIView!

Next, add the following extension:

// MARK: - Private
private extension SlideInPresentationController {
  func setupDimmingView() {
    dimmingView = UIView()
    dimmingView.translatesAutoresizingMaskIntoConstraints = false
    dimmingView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
    dimmingView.alpha = 0.0

Here you create the dimming view, prepare it for Auto Layout and set its background color. Notice you don’t add it to a superview yet. You’ll do that when the presentation transition starts, as you’ll see later in this section.

That presented controller needs to make itself scarce when you tap the dimmed view. Add the following beneath setupDimmingView() to make that happen:

@objc func handleTap(recognizer: UITapGestureRecognizer) {
  presentingViewController.dismiss(animated: true)

Here you create a UITapGestureRecognizer handler that dismisses the controller.

Of course, you’ll need to write that UITapGestureRecognizer, so add the following to the bottom of setupDimmingView():

let recognizer = UITapGestureRecognizer(
  target: self, 
  action: #selector(handleTap(recognizer:)))

This adds a tap gesture to the dimming view and links it to the action method you just added.

Finally, add a call to setupDimmingView() at the end of init(presentedViewController:presenting:direction:):


Override Presentation Controller Methods

Before you can start customizing the transition, you have to override four methods and a property from UIPresentationController. The default methods don’t do anything, so there’s no need to call super.

First, for a smooth transition, override presentationTransitionWillBegin() to make the dimming view fade in along with the presentation. Add the following code to the main class definition inside of SlideInPresentationController.swift:

override func presentationTransitionWillBegin() {
  guard let dimmingView = dimmingView else {
  // 1
  containerView?.insertSubview(dimmingView, at: 0)

  // 2
    NSLayoutConstraint.constraints(withVisualFormat: "V:|[dimmingView]|",
      options: [], metrics: nil, views: ["dimmingView": dimmingView]))
    NSLayoutConstraint.constraints(withVisualFormat: "H:|[dimmingView]|",
      options: [], metrics: nil, views: ["dimmingView": dimmingView]))

  guard let coordinator = presentedViewController.transitionCoordinator else {
    dimmingView.alpha = 1.0

  coordinator.animate(alongsideTransition: { _ in
    self.dimmingView.alpha = 1.0

Here’s what this code does:

  1. UIPresentationController has a property named containerView. It holds the view hierarchy of the presentation and presented controllers. This section is where you insert the dimmingView into the back of the view hierarchy.
  2. Next, you constrain the dimming view to the edges of the container view so that it fills the entire screen.
  3. transitionCoordinator of UIPresentationController has a very cool method to animate things during the transition. In this section, you set the dimming view’s alpha to 1.0 along with the presentation transition.

Now, you’ll hide the dimming view when you dismiss the presented controller. Override of dismissalTransitionWillBegin() by adding this code after the previous overridden method:

override func dismissalTransitionWillBegin() {
  guard let coordinator = presentedViewController.transitionCoordinator else {
    dimmingView.alpha = 0.0

  coordinator.animate(alongsideTransition: { _ in
    self.dimmingView.alpha = 0.0

Similar to presentationTransitionWillBegin(), you set the dimming view’s alpha to 0.0 alongside the dismissal transition. This gives the effect of fading the dimming view.

This next override will respond to layout changes in the presentation controller’s containerView. Add this code after the previous overridden method:

override func containerViewWillLayoutSubviews() {
  presentedView?.frame = frameOfPresentedViewInContainerView

Here you reset the presented view’s frame to fit any changes to the containerView frame.

Next, you’ll give the size of the presented view controller’s content to the presentation controller. Add this code after the previous overridden method:

override func size(forChildContentContainer container: UIContentContainer,
                   withParentContainerSize parentSize: CGSize) -> CGSize {
  switch direction {
  case .left, .right:
    return CGSize(width: parentSize.width*(2.0/3.0), height: parentSize.height)
  case .bottom, .top:
    return CGSize(width: parentSize.width, height: parentSize.height*(2.0/3.0))

This method receives the content container and parent view’s size, and then it calculates the size for the presented content. In this code, you restrict the presented view to 2/3 of the screen by returning 2/3 the width for horizontal and 2/3 the height for vertical presentations.

In addition to calculating the size of the presented view, you need to return its full frame. To do this you’ll override frameOfPresentedViewInContainerView. Below the properties at the top of the class definition, add the following:

override var frameOfPresentedViewInContainerView: CGRect {
  var frame: CGRect = .zero
  frame.size = size(forChildContentContainer: presentedViewController, 
                    withParentContainerSize: containerView!.bounds.size)

  switch direction {
  case .right:
    frame.origin.x = containerView!.frame.width*(1.0/3.0)
  case .bottom:
    frame.origin.y = containerView!.frame.height*(1.0/3.0)
    frame.origin = .zero
  return frame

Have a look at this code section-by-section:

  1. You declare a frame and give it the size calculated in size(forChildContentContainer:withParentContainerSize:).
  2. For .right and .bottom directions, you adjust the origin by moving the x origin (.right) and y origin (.bottom) 1/3 of the width or height.

With all the overrides done, you’re ready to put finishing touches on the transitions!

Implementing the Presentation Styles

Remember in the previous section how you created the transitioningDelegate? Well, it’s there but not doing much at the moment. It’s badly in need of some additional implementation.

Open SlideInPresentationManager.swift, locate the UIViewControllerTransitioningDelegate extension and add the following to it:

func presentationController(
  forPresented presented: UIViewController,
  presenting: UIViewController?,
  source: UIViewController
) -> UIPresentationController? {
  let presentationController = SlideInPresentationController(
    presentedViewController: presented,
    presenting: presenting,
    direction: direction
  return presentationController

Here you instantiate a SlideInPresentationController with the direction from SlideInPresentationManager. You return it to use for the presentation.

Now you’re making things happen! Build and run the app. Tap Summer, Winter and Medal Count to see your fancy new presentation styles in action.

Medal count

Quite a difference, don’t you think? The new presentation styles look sharp, but all the presented views still slide in from the bottom.


The client wants the Summer and Winter menus to slide in from the side. You’ll need to flex your animation muscles to make this happen.

Creating the Animation Controller

To add a custom animation transition, you’ll create a subclass of NSObject that conforms to UIViewControllerAnimatedTransitioning.

For complex animations you’d usually create two controllers — one for presentation and one for dismissal. In the case of this app, dismissal mirrors presentation, so you only need one animation controller.

Go to File ▸ New ▸ File…, choose iOS ▸ Source ▸ Cocoa Touch Class and click Next. Set the name to SlideInPresentationAnimator, make it a subclass of NSObject and set the language to Swift.

Click Next and set the group to Presentation and then click Create to make your new file. Open SlideInPresentationAnimator.swift and replace its contents with the following:

import UIKit

final class SlideInPresentationAnimator: NSObject {
  // 1
  // MARK: - Properties
  let direction: PresentationDirection

  let isPresentation: Bool
  // MARK: - Initializers
  init(direction: PresentationDirection, isPresentation: Bool) {
    self.direction = direction
    self.isPresentation = isPresentation

Here you declare:

  1. direction that tells the animation controller the direction from which it should animate the view controller’s view.
  2. isPresentation to tell the animation controller whether to present or dismiss the view controller.
  3. An initializer that accepts the two declared values above.

Next, add conformance to UIViewControllerAnimatedTransitioning by adding the following extension:

// MARK: - UIViewControllerAnimatedTransitioning
extension SlideInPresentationAnimator: UIViewControllerAnimatedTransitioning {
  func transitionDuration(
    using transitionContext: UIViewControllerContextTransitioning?
  ) -> TimeInterval {
    return 0.3

  func animateTransition(
    using transitionContext: UIViewControllerContextTransitioning
  ) {}

The protocol has two required methods — one to define how long the transition takes (0.3 seconds in this case) and one to perform the animations. The animation method is a stub to keep the compiler happy.

Replace the animateTransition(using:) stub with the following:

func animateTransition(
    using transitionContext: UIViewControllerContextTransitioning) {
  // 1
  let key: UITransitionContextViewControllerKey = isPresentation ? .to : .from

  guard let controller = transitionContext.viewController(forKey: key) 
    else { return }
  // 2
  if isPresentation {

  // 3
  let presentedFrame = transitionContext.finalFrame(for: controller)
  var dismissedFrame = presentedFrame
  switch direction {
  case .left:
    dismissedFrame.origin.x = -presentedFrame.width
  case .right:
    dismissedFrame.origin.x = transitionContext.containerView.frame.size.width
  case .top:
    dismissedFrame.origin.y = -presentedFrame.height
  case .bottom:
    dismissedFrame.origin.y = transitionContext.containerView.frame.size.height
  // 4
  let initialFrame = isPresentation ? dismissedFrame : presentedFrame
  let finalFrame = isPresentation ? presentedFrame : dismissedFrame
  // 5
  let animationDuration = transitionDuration(using: transitionContext)
  controller.view.frame = initialFrame
    withDuration: animationDuration,
    animations: {
      controller.view.frame = finalFrame
  }, completion: { finished in
    if !self.isPresentation {

I did say this one does the heavy lifting! Here’s what each section does:

  1. If this is a presentation, the method asks the transitionContext for the view controller associated with .to. This is the view controller you’re moving to. If dismissal, it asks the transitionContext for the view controller associated with .from. This is the view controller you’re moving from.
  2. If the action is a presentation, your code adds the view controller’s view to the view hierarchy. This code uses the transitionContext to get the container view.
  3. Calculate the frames you’re animating from and to. The first line asks the transitionContext for the view’s frame when it’s presented. The rest of the section tackles the trickier task of calculating the view’s frame when it’s dismissed. This section sets the frame’s origin so it’s just outside the visible area based on the presentation direction.
  4. Determine the transition’s initial and final frames. When presenting the view controller, it moves from the dismissed frame to the presented frame — vice versa when dismissing.
  5. Lastly, this method animates the view from initial to final frame. If this is a dismissal, you remove the view controller’s view from the view hierarchy. Note that you call completeTransition(_:) on transitionContext to inform the transition has finished.

Wiring Up the Animation Controller

You’re at the last step of building the transition: Hooking up the animation controller!

Open SlideInPresentationManager.swift and add the following two methods to the end of UIViewControllerTransitioningDelegate extension:

func animationController(
  forPresented presented: UIViewController,
  presenting: UIViewController,
  source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
  return SlideInPresentationAnimator(direction: direction, isPresentation: true)

func animationController(
  forDismissed dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
  return SlideInPresentationAnimator(direction: direction, isPresentation: false)

The first method returns the animation controller for presenting the view controller. The second returns the animation controller for dismissing the view controller. Both are instances of SlideInPresentationAnimator, but they have different isPresentation values.

Build and run the app. Check out those transitions! You should see a smooth slide-in animation from the left when you tap Summer. For Winter, it comes from the right, and Medal Count comes from the bottom.


Your result is exactly what you set out to do!

It works great… as long as the device is in portrait orientation. Try rotating to landscape.


The good news is that you’ve done the hardest part! The transitions work perfectly. In this section, you’ll make the effect work beautifully on all devices and both orientations.

Build and run the app again, but this time run it on an iPhone SE. You can use the simulator if you don’t have the actual device. Try opening the Summer menu in landscape. See anything wrong here?
Well, no. This actually looks great! Take a victory lap around your desk.

But what happens when you try to bring up the medal count? Select a year from the menu and tap Medal Count. You should see the following screen:
SlideInPresentationController restricts the view to 2/3 of the screen, leaving little space to show the medal count view. If you ship the app like this, you’re sure to hear complaints.

Fortunately for you, adaptivity is a thing. The iPhone has .regular height size class in portrait and .compact height size class in landscape. All you have to do is make a few alterations to the presentation to make use of this feature!

UIPresentationController has a delegate that conforms to UIAdaptivePresentationControllerDelegate, and it defines several methods to support adaptivity. You’ll use two of them in a moment.

First, you’ll make SlideInPresentationManager the delegate of SlideInPresentationController. This is the best option because the controller you choose to present determines whether the app should support compact height or not.

For example, GamesTableViewController looks correct in compact height, so there’s no need to limit its presentation. However, you do want to adjust the presentation for MedalCountViewController.

Open SlideInPresentationManager.swift and add the following below direction:

var disableCompactHeight = false

Here you add disableCompactHeight to indicate if the presentation supports compact height.

Next, add an extension that conforms to UIAdaptivePresentationControllerDelegate and implements adaptivePresentationStyle(for:traitCollection:) as follows:

// MARK: - UIAdaptivePresentationControllerDelegate
extension SlideInPresentationManager: UIAdaptivePresentationControllerDelegate {
  func adaptivePresentationStyle(
    for controller: UIPresentationController,
    traitCollection: UITraitCollection
  ) -> UIModalPresentationStyle {
    if traitCollection.verticalSizeClass == .compact && disableCompactHeight {
      return .overFullScreen
    } else {
      return .none

This method accepts a UIPresentationController and a UITraitCollection and returns the desired UIModalPresentationStyle.

Next, it checks if verticalSizeClass equals .compact and if compact height is disabled for this presentation.

  • If yes, it returns a presentation style of .overFullScreen. This way, the presented view will cover the entire screen — not just 2/3 as defined in SlideInPresentationController.
  • If no, it returns .none, to stay with the implementation of UIPresentationController.

Find presentationController(forPresented:presenting:source:).
Set SlideInPresentationManager as the presentation controller’s delegate by adding the following line above the return statement:

presentationController.delegate = self

Finally, you’ll tell SlideInPresentationManager when to disable compact height.

Open MainViewController.swift and locate prepare(for:sender:). Find where the segue’s destination view controller is GamesTableViewController, and then add the following line to the if block:

slideInTransitioningDelegate.disableCompactHeight = false

Find where the segue’s destination view controller is MedalCountViewController and add the following to the if block:

slideInTransitioningDelegate.disableCompactHeight = true

Build and run the app, bring up a medal count and rotate the device to landscape. The view should now take the entire screen, as shown below:

This works great!

Overriding the presented controller

There’s still a niggly bit for the use case where you have a view that can only show in regular height. Maybe there’s something on there that’s just too tall to fit in a compact height. UIAdaptivePresentationControllerDelegate can help you.

Set it up by opening SlideInPresentationManager.swift and adding the following method to UIAdaptivePresentationControllerDelegate extension:

func presentationController(
  _ controller: UIPresentationController,
  viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle
) -> UIViewController? {
  guard case(.overFullScreen) = style else { return nil }
  return UIStoryboard(name: "Main", bundle: nil)
    .instantiateViewController(withIdentifier: "RotateViewController")

This method accepts a UIPresentationController and a UIModalPresentationStyle. It returns a view controller that overrides the original controller to present, or nil if the original view controller should be presented.

If the presentation style is .overFullScreen it creates and returns a different view controller controller. This new controller is just a simple UIViewController with an image that tells the user to rotate the screen to portrait.

Build and run the app, bring up the medal count and rotate the device to landscape. You should see the message:

Rotate the device back to portrait to view the medal count again.

Where To Go From Here?

Congratulations! You made it through a world-class athletic journey (for your brain) and built a custom UIPresentationController.

You can download the completed version of the project using Download Materials at the top or bottom of this tutorial.

You’ve covered quite a bit! You learned how to customize and reuse a UIPresentationController to create neat slide-in effects from any direction.

You also learned how to adapt presentations for various devices and both orientations, as well as how to handle cases where the device can’t handle landscape orientation.

I’m sure you can come up with many more creative ideas for presentations in your app. I encourage you to try them out based on what you’ve learned in this tutorial.

To delve deeper into custom transitions, check out this Custom View Controller Presentation Transitions tutorial by Marin Todorov & Fabrizio Brancati. You’ll find some interesting videos on the topic in our Beginning iOS Animation video series.

For more on Adaptive Layouts, check out this adaptive layout in iOS tutorial by Adam Rush, or these adaptive layout video tutorials in the second section of our Mastering Auto Layout video series.

For more information on UIPresentationController, check out Apple’s documentation.

This iOS tutorial was a lot of fun to put together, and I’m keen to hear how it went for you. Bring your questions, blockers and discoveries to the forums below and let’s talk presentations! :]




More like this