Home > Back-end >  Open sheet and overwrite current sheet or provide internal navigationstack inside sheet
Open sheet and overwrite current sheet or provide internal navigationstack inside sheet

Time:11-13

So I have a button as shown below:

private var getStartedButton: some View {
    Button {
        showGetStartedSheet.toggle()
    } label: {
        Text("Get Started")
    }
    .sheet(isPresented: $showGetStartedSheet) {
        LoginUserSheetView()
            .presentationDetents([.fraction(0.70), .large])
    }
}

Which opens the LoginUserSheetView() view and has the following function inside:

private var userCreateAccount: some View {
    VStack(alignment: .center) {
        Text("New MapGliders? User register")
            .sheet(isPresented: $showUserRegisterSheet) {
                RegisterUserSheetView()
                    .presentationDetents([.fraction(0.70), .large])
            }
    }
}

The above code, then opens another sheet which presents the following code:

private var appleButton: some View {
    Button {
        // Hello
    } label: {
        HStack(alignment: .firstTextBaseline) {
            Image(systemName: "applelogo")
            Text("Hello")
        }
    }
}

The above code (lots has been removed) produces the following output:

https://im4.ezgif.com/tmp/ezgif-4-4ecfdb6d55.gif

As you can see the video above, the second sheet opens on top of the old sheet, I would like the sheet to be overwritten or create a navigation on a single sheet.

Does anyone know how I can close LoginUserSheetView() when RegisterUserSheetView() is opened? or how could I make the sheet be overwritten or even use a navigation to navigate to RegisterUserSheetView() when on the LoginUserSheetView() is opened.

CodePudding user response:

The first option is to use sheet(item:). But this does dismiss the sheet and they makes it reappear with the new value

struct DynamicOverlay: View {
    @State var selectedOverlay: OverlayViews? = nil
    var body: some View {
        VStack{
            Text("hello there")
            Button("first", action: {
                selectedOverlay = .first
            })
            
        }
        .sheet(item: $selectedOverlay){ passed in
            passed.view($selectedOverlay)
        }
    }
    enum OverlayViews: String, Identifiable{
        var id: String{
            rawValue
        }
        case first
        case second
        
        @ViewBuilder func view(_ selectedView: Binding<OverlayViews?>) -> some View{
            switch self{
            case .first:
                ZStack {
                    Color.blue
                        .opacity(0.5)
                    
                    Button {
                        selectedView.wrappedValue = .second
                    } label: {
                        Text("Next")
                    }
                }
            case .second:
                ZStack {
                    
                    Color.red
                        .opacity(0.5)
                    Button("home") {
                        selectedView.wrappedValue = nil
                    }
                }
                
            }
        }
    }
}

The second option doesn't have the animation behavior but required a small "middle-man" View

import SwiftUI

struct DynamicOverlay: View {
    @State var selectedOverlay: OverlayViews = .none
    @State var presentSheet: Bool = false
    var body: some View {
        VStack{
            Text("hello there")
            Button("first", action: {
                selectedOverlay = .first
                presentSheet = true
            })
            
        }
        .sheet(isPresented: $presentSheet){
            //Middle-main
            UpdatePlaceHolder(selectedOverlay: $selectedOverlay)
        }
    }
    enum OverlayViews{
        case first
        case second
        case none
        
        @ViewBuilder func view(_ selectedView: Binding<OverlayViews>) -> some View{
            switch self{
            case .first:
                ZStack {
                    Color.blue
                        .opacity(0.5)
                    
                    Button {
                        selectedView.wrappedValue = .second
                    } label: {
                        Text("Next")
                    }
                }
            case .second:
                ZStack {
                    
                    Color.red
                        .opacity(0.5)
                    Button("home") {
                        selectedView.wrappedValue = .none
                    }
                }
            case .none:
                EmptyView()
            }
        }
    }
    //Needed to reload/update the selected item on initial presentation
    struct UpdatePlaceHolder: View {
        @Binding var selectedOverlay: OverlayViews
        
        var body: some View{
            selectedOverlay.view($selectedOverlay)
            
        }
    }
    
}

You can read a little more on why you need that intermediate view here SwiftUI: Understanding .sheet / .fullScreenCover lifecycle when using constant vs @Binding initializers

  • Related