5

How to achieve what the following Objective-C code achieves with SwiftUI? I haven't been able to get a firm grasp on the ideas presented.

    [self presentViewController:messageViewController animated:YES completion:nil];
  • You want to look for `UIViewRepresentable`, there are plenty of tutorials showing how to use UIKit views and view controllers inside SwiftUI. – Andrew Jun 25 '20 at 08:29
  • I am little bit confused of what the point of the question is. Do you want to know how to present any View with FullScreen? – Kyokook Hwang Jun 25 '20 at 10:47
  • @Kyokook You're right. I want to know how to present a modal view in the middle of the screen on top of the super view. –  Jun 25 '20 at 11:36

2 Answers2

5

As there is no provided related code, so in pseudo-code it would look like the following

struct YourParentView: View {
   @State private var presented = false
   var body: some View {

      // some other code that activates `presented` state

      SomeUIElement()
         .sheet(isPresented: $presented) {
             YourMessageViewControllerRepresentable()
         }
   }
}
Asperi
  • 123,447
  • 8
  • 131
  • 245
  • Thank you for your answer. It definitely improved my understanding after tinkering a little bit. However, I have a follow-up question: I've read a little about Representables but they seem to be designed to use UIViews. Is this also the way to use some old Objective C View in sheet? In other words, are Representables used for wrapping other views than UIView to present a view on top of the superview when a particular action is taken? –  Jun 25 '20 at 14:10
  • 1
    @Ali, it is possible to represent either exact UIView, including all subviews of course, (by UIViewRepresentable), or entire UIViewController (by UIViewControllerRepresentable). If you have set up Objective-C/Swift bridge correctly then your UIView/UIViewController will work as well - there is no differences. – Asperi Jun 25 '20 at 14:15
2

Until ios 13.x, there is no way provided by SwiftUI. So, I had same need so wrote a custom modifier of View to achieve it.

extension View {
    func uiKitFullPresent<V: View>(isPresented: Binding<Bool>, style: UIModalPresentationStyle = .fullScreen, content: @escaping (_ dismissHandler: @escaping () -> Void) -> V) -> some View {
        self.modifier(FullScreenPresent(isPresented: isPresented, style: style, contentView: content))
    }
}

struct FullScreenPresent<V: View>: ViewModifier {
    @Binding var isPresented: Bool
    @State private var isAlreadyPresented: Bool = false
    
    let style: UIModalPresentationStyle
    let contentView: (_ dismissHandler: @escaping () -> Void) -> V
    
    @ViewBuilder
    func body(content: Content) -> some View {
        if isPresented {
            content
                .onAppear {
                    if self.isAlreadyPresented == false {
                        let hostingVC = UIHostingController(rootView: self.contentView({
                            self.isPresented = false
                            self.isAlreadyPresented = false
                            UIViewController.topMost?.dismiss(animated: true, completion: nil)
                        }))
                        hostingVC.modalPresentationStyle = self.style
                        UIViewController.topMost?.present(hostingVC, animated: true) {
                            self.isAlreadyPresented = true
                        }
                    }
                }
        } else {
            content
        }
    }
}

And, you can use it as the following.

.uiKitFullPresent(isPresented: $isShowingPicker, content: { closeHandler in
    SomeFullScreenView()
        .onClose(closeHandler) // '.onClose' is a custom extension function written. you can invent your own way to call 'closeHandler'.
})

content parameter of .uiKitFullPresent is a closure which has a callback handler as its parameter. you can use this callback to dismiss the presented view.

It's worked well so far. looks little bit tricky though.

As you may know, iOS 14 will bring us a method to present any view in the way you want. Check fullScreenCover() out.

Regarding presenting UIViewController written by Objective-C, it would be possible as Asperi mentioned on his post.

UPDATE
Here is a full source code I am using so far. https://gist.github.com/fullc0de/3d68b6b871f20630b981c7b4d51c8373

Kyokook Hwang
  • 2,418
  • 19
  • 36