(lldb) thread step-out

Back-port .fullScreenCover to SwiftUI 1.0

Modal presentation in SwiftUI

SwiftUI 2.0 presented on WWDC20 brings us a lot of small improvements and additions to the APIs. In iOS 13 we already had API to open views modally in a bottom-rising sheet, but whatever the contents presentation mode was, there was no way to present it full screen.Real-life example: early versions of our app had to present Camera of UIImagePickerController in such sheet which looked very stupid.

One of the new APIs adds an ability to open views modally - fullScreenCover(isPresented:onDismiss:content:).Unfortunately, this view modifier is available only on iOS 14 and higher.

How can it be back ported to iOS 13?

Short answer: with help of UIKit and thanks to its interoperability with SwiftUI.
  1. As one can remember, UIKit is managing view hierarchy by means of UIViewControllers which can serve as presenters to each other. In a simple cases presentation transition (animation and which part of the screen the presented controller's view will take) depends on presenting controller's .presentationStyle;
  2. SwiftUI can wrap UIViewControllers into UIViewControllerRepresentable views and embed into hierarchy like any other View. Such controllers have 2 important methods (makeUIViewController, dismantleUIViewController) which will help us manage presentation process
So, generally the plan is:
  1. Add invisible UIViewController to parent SwiftUI view
  2. Provide this controller with a child SwitUI view that needs to be presented in a full screen modal
  3. When this controller appears in the hierarchy, it will present the child using UIKit APIs
  4. When the child should be dismissed, the controller should be removed from the hierarchy

Empowered by the beauty of ViewModifiers we can keep code almost the same!

Production code will be more complex, but for the sake of simplicity let's omit edge cases:

Code


Following steps

[1] More about approaches to backwards compatibility in SwiftUI

[2] Backport of AppStorage for iOS 13 which can be used as a drop-in replacement


27/09/2020