Reproducing Popular iOS Controls - Part 29: | Ray Wenderlich Videos

In this video you'll learn how to implement a custom UIPresentationController.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/5298-reproducing-popular-ios-controls/lessons/29
1 Like

Strange… I downloaded and ran the final project of Video 29,
It runs fine for the first launch but crashes from next time onwards. I can’t figure out the reason of crash.

Huh… that’s really bizarre. What’s your Xcode version? And do you get an error message? Could you paste it here if you do?

1 Like

Hi Leamars,

I am using Xcode 10 beta 5. It is strange that the project is working fine for the first time when I run through Xcode but when I disconnect it from Xcode and run independently on device the app always crashes.

I am running iOS 11.4.1 on my device, iOS 12 on simulator but the app still crashes.
I also tested on Xcode 9, same issue.

I found the crash log on my device and I have attached it.
Maps.crash.zip (12.0 KB)

Also I am not able to interact with Map when LocationsViewController is presented. How to make presenting controller receive touch events?

I honestly don’t know what to tell you about the crash. I’ve ran it on a pre iOS 12 device, and it’s working fine for me. From the crash logs it looks like there’s something wrong with the storyboards & it’s execution on your device, but I can’t really pin point what’s going on. Try deleting the app from the phone, deleting it from your computer completely, and re-downloading it and running from scratch.

You can’t interact with the map because a view does not receive touch events when it’s presenting. Going into that would be a little over the top for this course, but here’s a great articles to read up on the topic and a solution for what you’re trying to achieve: Presentation Controllers and Adaptive Presentations | PSPDFKit

There’s also this open source project you can check out that might help you achieve what you want. Custom View Controller presentations, the right way. | by Raul Riera | Medium

Hope that helps!

1 Like

I tried out what I mentioned above to make sure it would work for our needs, and it does. Here are the implementation details:

Add a new PSPDFTouchForwardingView class to your project.

import UIKit

// This class allows the "presentedController" to receive touches
// https://pspdfkit.com/blog/2015/presentation-controllers/
final class PSPDFTouchForwardingView: UIView {
  
  final var passthroughViews: [UIView] = []
  
  override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard let hitView = super.hitTest(point, with: event) else { return nil }
    guard hitView == self else { return hitView }
    
    for passthroughView in passthroughViews {
      let point = convert(point, to: passthroughView)
      if let passthroughHitView = passthroughView.hitTest(point, with: event) {
        return passthroughHitView
      }
    }
    
    return self
  }
}

Add a new touchForwardingView var to the DraggablePresentationController:

private lazy var touchForwardingView: PSPDFTouchForwardingView? = {
    guard let containerView = containerView else { return nil }
    return PSPDFTouchForwardingView(frame: containerView.bounds)
  }()

Then change the presentationTransitionWillBegin method to look like this where you add the touchForwardingView at index 0 of the containerView:

override func presentationTransitionWillBegin() {
    guard let containerView = containerView else { return }
    
    touchForwardingView!.passthroughViews = [presentingViewController.view]
    containerView.insertSubview(touchForwardingView!, at: 0)
    
    containerView.insertSubview(dimmingView, at: 1)
    dimmingView.alpha = 0
    dimmingView.backgroundColor = .black
    dimmingView.frame = containerView.frame
  }
3 Likes

Thanks you Leamars. I am able to interact with the Map with your help.

Thanks for pointing out to these resources. I am trying to build similar interface for one of my app. This will really help.

About the crash happening on this project, I couldn’t figure out the reason, but I can deal with it. I am able to reproduce the same functionality in my own app and it is working fine. :slight_smile:

1 Like

Awesome! Glad it worked out (:

A problem with this code is that it wont dismiss the presented controller when pressing back on the navigation controller without additional code.

Here is the code to dismiss the presented controller. Place on the parent controller. No modification necessary to the back button

    override func willMove(toParentViewController parent: UIViewController?)
{
    super.willMove(toParentViewController: parent)
    if parent == nil
    {
        self.presentedViewController?.dismiss(animated: true)
    }
}
1 Like

@slicedavocado Thank you for sharing the solution - much appreciated! :]

You saved my week. It works. Thank you so much.

Hi @leamars! Great tutorial!

I’m trying to give the “bottom sheet” dynamic values for its size instead of pre-defined screen percentages. What do I need to modify in order to, let’s say, pass to the DraggablePresentationController the size of the open, collapsed or halfway points?
I mean, let’s say I want my open state to have 400.0 points, my half 200.0 and my collapsed 0.0, How to achieve such thing?

Also, why have you created this initialiser if none of these properties are ever used?

init(viewControllerToPresent: UIViewController, presentingViewController: UIViewController) {
    self.vcToPresent = viewControllerToPresent
    self.presentingVC = presentingViewController
  }

@leamars Can you please help with this when you get a chance? Thank you - much appreciated! :]

@vasanthkumar Really glad you like it!

@fschnek Do you still have issues with your deleted post?