SwiftUI dismiss modal

前端 未结 13 2133
闹比i
闹比i 2020-11-29 23:23

Since SwiftUI is declarative there is no dismiss methode. How can is add a dismiss/close button to the DetailView?



        
相关标签:
13条回答
  • 2020-11-30 00:09

    In Xcode 11.0 beta 7, the value is now wrapped, the following function is working for me:

    func dismiss() {
        self.presentationMode.wrappedValue.dismiss()
    }
    
    0 讨论(0)
  • 2020-11-30 00:09

    The modal views in SwiftUI seem to be simple until you start using them in a List or Form views. I have created a small library which wraps all the edge cases and makes the using of modal views the same as NavigationView-NavigationLink pair.

    The library is open-sourced here: https://github.com/diniska/modal-view. You can include it into the project using Swift Package Manager, or just by copying the single file that the library includes.

    The solution for your code would be:

    struct DetailView: View {
        var dismiss: () -> ()
        var body: some View {
            Text("Detail")
            Button(action: dismiss) {
                Text("Click to dismiss")
            }
        }
    }
    
    struct ContentView : View {
        var body: some View {
            ModalPresenter {
                ModalLink(destination: DetailView.init(dismiss:)) {
                    Text("Click to show")
                }
            }
        }
    }
    

    Additionally, there is an article with full description and examples: How to present modal view in SwiftUI

    0 讨论(0)
  • 2020-11-30 00:10

    Seems that for Xcode 11 Beta 7 (this is on build 11M392r of Xcode) it's slightly different.

    @Environment(\.presentationMode) var presentation
    
    
    Button(action: { self.presentation.wrappedValue.dismiss() }) { Text("Dismiss") }
    
    0 讨论(0)
  • 2020-11-30 00:10

    One way to do this might be to declare you own modifier for modal presentation and dismissal.

    extension View {
    
      func showModal<T>(_ binding: Binding<Bool>, _ view: @escaping () -> T) -> some View where T: View {
    
        let windowHeightOffset = (UIApplication.shared.windows.first?.frame.height ?? 600) * -1
    
        return ZStack {
    
          self
    
          view().frame(maxWidth: .infinity, maxHeight: .infinity).edgesIgnoringSafeArea(.all).offset(x: 0, y: binding.wrappedValue ? 0 : windowHeightOffset)
    
        }
    
      }
    }
    

    Then you can use the modifier on any view that you wish to tell how to display a view and dismiss that view. Just like a popover or sheet modifier.

    struct ContentView: View {
    
      @State var showModal = false
    
      var body: some View {
    
        Text("Show").foregroundColor(.blue).onTapGesture {
          withAnimation(.easeIn(duration: 0.75)) {
            self.showModal = true
          }
        }.showModal($showModal, {
    
          Text("Dismiss").foregroundColor(.blue).onTapGesture {
            withAnimation(.easeIn(duration: 0.75)) {
              self.showModal = false
            }
          }
    
        })
    
    
      }
    }    
    

    The presentation is full screen from the top, if you wish it to come from the side, change the transition inside the modifier to leading or trailing. Other transitions would work too, like opacity or scale.

    0 讨论(0)
  • 2020-11-30 00:16

    Here's a way to dismiss the presented view.

    struct DetailView: View {
        @Binding
        var dismissFlag: Bool
    
        var body: some View {
            Group {
                Text("Detail")
                Button(action: {
                    self.dismissFlag.toggle()
                }) {
                    Text("Dismiss")
                }
            }
    
        }
    }
    
    struct ContentView : View {
        @State var dismissFlag = false
    
        var body: some View {
            Button(action: {
                self.dismissFlag.toggle()
            })
            { Text("Show") }
                .presentation(!dismissFlag ? nil :
                    Modal(DetailView(dismissFlag: $dismissFlag)) {
                    print("dismissed")
                })
        }
    }
    

    0 讨论(0)
  • 2020-11-30 00:16

    Automatically pop if in Navigation or dismiss if Modal


    Just take the presentationMode from the environment in the destination view and dismiss the wrappedValue from it:

    struct DestinationView: View {
        @Environment(\.presentationMode) private var presentationMode
    
        var body: some View {
            Button("Dismiss") {
                self.presentationMode.wrappedValue.dismiss()
            }
        }
    }
    
    

    Demo ( pop / dismiss )

    0 讨论(0)
提交回复
热议问题