12

I am using view controller containment to manage a set of child view controllers which should be able to modally present other view controllers in a custom manner.

I have run into an issue where the definesPresentationContext property is not used when a presenting from a view controller using UIModalPresentationStyle.custom

As an example, I have three view controllers: ROOT, A, and B

ROOT
 |_ A

A is the child of ROOT. I would like to present B modally from A while using custom UIPresentationController, UIViewControllerTransitioningDelegate, and UIViewControllerAnimatedTransitioning.

So I do the following inside the code for controller A (note controller A has definesPresentationContext set to true):

func buttonPressed(_ sender: Any?) {
    let presentationController = MyCustomPresentation()

    let controllerToPresent = B()

    controllerToPresent.modalTransitionStyle = .custom
    controllerToPresent.transitioningDelegate = presentationController

    present(controllerToPresent, animated: true, completion: nil)
}

However, inside my presentation controller (which is also my UIViewControllerAnimatedTransitioning) I encounter the following problem:

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let fromVC = transitionContext.viewController(forKey: .from)
    let toVC = transitionContext.viewController(forKey: .to)

    if let fromVC = fromVC as? A,
        let toVC = toVC as? B {
        //Do the presentation from A to B
    }
}

In this function, where I expect fromVC to be of type A, it is actually ROOT. Despite the fact that A specifies definesPresentationContext.

So I figure this is because I'm using UIModalPresentationStyle.custom. So I change it to UIModalPresentationStyle.overCurrentContext

This causes iOS to correctly read the definesPresentationContext property from A, and my animateTransition function now gets called with the correct from view controller, but:

Because my modal presentation style is no longer .custom, the following method in my transitioning delegate no longer gets called

func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController?

So my presentation controller becomes unused.

I want a .custom modal transition style which respects definesPresentationContext. Is this possible? Am I missing something?

Basically, I want a custom modal presentation within the current context.

simeon
  • 4,466
  • 2
  • 38
  • 42
  • Have you tried setting the transitioning delegate also in `A`? Before this line: `present(controllerToPresent, animated: true, completion: nil)`. try this: `self.transitioningDelegate = presentationController` I suggest this when using: `UIModalPresentationStyle.overCurrentContext` – vicegax Aug 01 '17 at 22:47

1 Answers1

0

In your UIPresentationController subclass, override shouldPresentInFullscreen as follows:

 override var shouldPresentInFullscreen: Bool {
     get {
         return false
     }
 }

As per the UIPresentationController header:

// By default each new presentation is full screen.
// This behavior can be overriden with the following method to force a current context presentation.
// (Default: YES)
@property(nonatomic, readonly) BOOL shouldPresentInFullscreen;

This along with definesPresentationContext should do the trick.

capikaw
  • 12,232
  • 2
  • 43
  • 46
  • 1
    Thank you for your answer. I checked my UIPresentationController subclass and found it was already returning `false` for `shouldPresentInFullscreen` — but it's still not given the view controller further down the tree defining the presentation context, and getting the root vc instead. – simeon Sep 11 '17 at 12:33
  • Does not seem to work. Right now I assume that `definesPresentationContext ` does not work with `UIModalPresentationStyle.custom` – Wizard Jul 14 '18 at 14:19