0

Question

How can one implement a custom gesture-driven transition between two UIViewControllers, where the initial view controller supports several interface orientations, but the final view controller is restricted to, say, .portrait?

Details

I looking to implement a gesture-driven transition, similar to the one found in the stock iPhone Camera App. Here, you can leave the gallery, by dragging the photo towards the bottom of the screen, and once dragged sufficiently far, the gallery is dismissed by lifting the finger.

I have found many sources across the web that explain how to achieve this behavior, and I think the most prominent solutions are the following:

  1. Subclass UIViewControllerAnimatedTransitioning for the custom animation and control it with a UIPercentDrivenInteractiveTransition and a UIPanGestureRecognizer.

  2. Present the child UIViewController (i.e. the gallery) with .modalPresentationStyle = .overFullScreen, and again use a UIPanGestureRecognizer to apply position and size changes as needed. The dismiss animation can then be triggered when the pan gesture ends.

My problem is that both approaches fail when the child and parent view controllers have different orientations. This is, again, best explained with the stock Camera App: In the camera view (the parent view), a rotation of the phone from portrait to landscape does not rearrange the complete UI, but only rotates some buttons. I needed similar behavior, and achieved this by overriding supportedInterfaceOrientations to return .portrait. However, the gallery view does rearrange its UI according to orientation, so the supportedInterfaceOrientations are not restricted for the child view.

So while in the stock app, I can nicely rotate the phone into landscape, and still use a gesture to dismiss the gallery, in my implementation this fails in the following way:

  1. For the first approach, the UIPanGestureRecognizer changes its state to ended practically immediately, cancelling the animation and leaving my UI in a somewhat undefined state with both view controllers visible.

  2. In the second approach, the parent view controller remains in control of the device orientation, not allowing the child to rearrange its UI into landscape mode.

Wondering if existing frameworks have similar issues, I stumbled upon the Hero Library, and my case 1 can be perfectly reproduced from an example, if the landscape orientations are activated in the App's Deployment Info, and the first view controller is locked into portrait mode by adding this block to the class FirstViewController.

override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait }
jscs
  • 63,694
  • 13
  • 151
  • 195

1 Answers1

0

You shouldn't prevent the “camera” screen from the rotation. Prevent camera's view from the rotation instead. Check this answer out: https://stackoverflow.com/a/38874886/4637398

Here is a demo of my rough copy of Camera layout (probably not the coolest realization of view rotation blocking): https://www.dropbox.com/s/wqheb9i6mk6bql3/Camera-like.zip?dl=0

Anton Lovchikov
  • 473
  • 1
  • 3
  • 13