Present a new view in SwiftUI

For iOS 14 and Xcode 12:

struct ContentView: View {
    @State private var isPresented = false

var body: some View {
    Button("Show Modal with full screen") {
        self.isPresented.toggle()
    }
    .fullScreenCover(isPresented: $isPresented, content: FullScreenModalView.init)
    }
}
struct FullScreenModalView: View {
     @Environment(\.presentationMode) var presentationMode

var body: some View {
    VStack {
        Text("This is a modal view")
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .background(Color.red)
    .edgesIgnoringSafeArea(.all)
    .onTapGesture {
        presentationMode.wrappedValue.dismiss()
    }
}
}

Hope this answer can help you all! Comment below about your result.

Ref: This Link


To show a modal (iOS 13 style)

You just need a simple sheet with the ability to dismiss itself:

struct ModalView: View {
    @Binding var presentedAsModal: Bool
    var body: some View {
        Button("dismiss") { self.presentedAsModal = false }
    }
}

And present it like:

struct ContentView: View {
    @State var presentingModal = false
    
    var body: some View {
        Button("Present") { self.presentingModal = true }
        .sheet(isPresented: $presentingModal) { ModalView(presentedAsModal: self.$presentingModal) }
    }
}

Note that I passed the presentingModal to the modal so you can dismiss it from the modal itself, but you can get rid of it.


To make it REALLY present fullscreen (Not just visually)

You need to access to the ViewController. So you need some helper containers and environment stuff:

struct ViewControllerHolder {
    weak var value: UIViewController?
}

struct ViewControllerKey: EnvironmentKey {
    static var defaultValue: ViewControllerHolder {
        return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)

    }
}

extension EnvironmentValues {
    var viewController: UIViewController? {
        get { return self[ViewControllerKey.self].value }
        set { self[ViewControllerKey.self].value = newValue }
    }
}

Then you should use implement this extension:

extension UIViewController {
    func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
        let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
        toPresent.modalPresentationStyle = style
        toPresent.rootView = AnyView(
            builder()
                .environment(\.viewController, toPresent)
        )
        NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "dismissModal"), object: nil, queue: nil) { [weak toPresent] _ in
            toPresent?.dismiss(animated: true, completion: nil)
        }
        self.present(toPresent, animated: true, completion: nil)
    }
}

Finally

you can make it fullscreen like:

struct ContentView: View {
    @Environment(\.viewController) private var viewControllerHolder: UIViewController?
    
    var body: some View {
        Button("Login") {
            self.viewControllerHolder?.present(style: .fullScreen) {
                Text("Main") // Or any other view you like
// uncomment and add the below button for dismissing the modal
            // Button("Cancel") {
            //       NotificationCenter.default.post(name: Notification.Name(rawValue: "dismissModal"), object: nil)
            //        }
            }
        }
    }
}

Tags:

Ios

Swiftui