Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Present a new view in SwiftUI

Tags:

ios

swiftui

I want to click a button and then present a new view like present modally in UIKit enter image description here

I have already seen "How to present a new view using sheets", but I don't want to attach it to the main view as a modal sheet.

And I don't want to use NavigationLink, because I don't want a new view and old view have a navigation relationship.

Thanks for your help...

like image 279
CH Wing Avatar asked Nov 20 '19 16:11

CH Wing


People also ask

How do I present and dismiss a view in SwiftUI?

The first option is to tell the view to dismiss itself using its presentation mode environment key. Any view can read its presentation mode using @Environment(\. presentationMode) , and calling wrappedValue. dismiss() on that will cause the view to be dismissed.

How do I present a sheet in SwiftUI?

To use a sheet, give it something to show (some text, an image, a custom view, etc), add a Boolean that defines whether the detail view should be showing, then attach it to your main view as a modal sheet. Important: If you're targeting iOS 14 or below, you should use @Environment(\.


2 Answers

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)             //        }             }         }     } } 
like image 160
Mojtaba Hosseini Avatar answered Sep 18 '22 17:09

Mojtaba Hosseini


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

like image 36
Sour LeangChhean Avatar answered Sep 18 '22 17:09

Sour LeangChhean