简体   繁体   中英

SwiftUI dismiss modal sheet presented from NavigationView (Xcode Beta 5)

I am attempting to dismiss a modal view presented via a .sheet in SwiftUI - called by a Button which is within a NavigationView s navigationBarItems , as per below:

struct ModalView : View {

    @Environment(\.presentationMode) var presentationMode  

    var body: some View {       
        Button(action: {
            self.presentationMode.value.dismiss()
        }, label: { Text("Save")})
    }   

}

struct ContentView : View {

    @State var showModal: Bool = false

    var body: some View {
         NavigationView { 
           Text("test")
           .navigationBarTitle(Text("Navigation Title Text"))
           .navigationBarItems(trailing:
               Button(action: {
                   self.showModal = true
               }, label: { Text("Add") })
                   .sheet(isPresented: $showModal, content: { ModalView() })
           )
        }
    }

}

The modal does not dismiss when the Save button is tapped, it just remains on screen. The only way to get rid of it is swiping down on the modal.

Printing the value of self.presentationMode.value always shows false so it seems to think that it hasn't been presented.

This only happens when it is presented from the NavigationView . Take that out and it works fine.

Am I missing something here, or is this a beta issue?

You need to move the .sheet outside the Button.

NavigationView {
  Text("test")
  .navigationBarTitle(Text("Navigation Title Text"))
  .navigationBarItems(trailing:
     Button("Add") {
       self.showModal = true
     }
  )
  .sheet(isPresented: $showModal, content: { ModalView() })
}

You can even move it outside the NavigationView closure.

NavigationView {
  Text("test")
  .navigationBarTitle(Text("Navigation Title Text"))
  .navigationBarItems(trailing:
     Button("Add") { self.showModal = true }
  )
}
.sheet(isPresented: $showModal, content: { ModalView() })

Notice you can also simplify the Button call if you have a simple text button.

The solution is not readily apparent in the documentation and most tutorials opt for simple solutions. But I really wanted a button in the NavigationBar of the sheet that would dismiss the sheet. Here is the solution in six steps:

  1. Set the DetailView to not show.
  2. Add a button to set the DetailView to show.
  3. Call the .sheet(isPresented modifier to display the sheet.
  4. Wrap the view that will appear in the sheet in a NavigationView because we want to display a .navigationBarItem button.
  5. PresentationMode is required to dismiss the sheet view.
  6. Add a button to the NavBar and call the dismiss method.

import SwiftUI

struct ContentView: View {
    // 1
    @State private var showingDetail = false
    var body: some View {
        VStack {
            Text("Hello, world!")
                .padding()
            Button("Show Detail") {
                showingDetail = true // 2
            }
            // 3
            .sheet(isPresented: $showingDetail) {
                // 4
                NavigationView {
                    DetailView()
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


struct DetailView: View {
    // 5
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        Text("Detail View!")
            // 6
            .navigationBarItems(leading: Button(action: {
                presentationMode.wrappedValue.dismiss()
            }) {
                Image(systemName: "x.circle")
                    .font(.headline)
                    .foregroundColor(.accentColor)
            })
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM