Group Group Group Group Group Group Group Group Group

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

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: https://pspdfkit.com/blog/2015/presentation-controllers/

There’s also this open source project you can check out that might help you achieve what you want. https://medium.com/@raulriera/custom-view-controller-presentations-the-right-way-53e8e8e8118b

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.