jifei
jifei

Reputation: 13

In SwiftUI, when the MyView popup sheet then dismissed, the MyView should be displayed instead of ListView

Here is three view,ContentView,ListView and MyView。Click first bottom icon show ListView,then click NavigationLink display MyView.Click the button display sheet,dismiss the sheet the ListView displayed on the screen.


struct ContentView: View {
    var body: some View {
        NavigationView {
            TabView {
                ListView().tabItem {
                        Label("list view", systemImage: "face.smiling")
                    }
                Text("list 2 content").tabItem {
                    Label("text", systemImage: "face.smiling")
                }
            }
        }
    }
}

struct ListView: View {
    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            LazyHStack(alignment: .top) {
                LazyVStack {
                    NavigationLink(destination: MyView()) {
                        Text("test")
                    }
                }
            }
        }
    }
}

struct MyView: View {
    @State private var isShowingSheet = false
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        Button(action: {
            isShowingSheet.toggle()
        }) {
            Text("Show Sheet")
        }
        .sheet(isPresented: $isShowingSheet,
               onDismiss: didDismiss)
        {
            VStack {
                Text("License Agreement")
                    .font(.title)
                    .padding(50)
                Text("""
                    Terms and conditions go here.
                """)
                .padding(50)
                Button("Dismiss",
                       action: { isShowingSheet.toggle() })
            }
        }
    }

    func didDismiss() {
        presentationMode.wrappedValue.dismiss()
    }
}

In MyView sheet dismissed,should display MyView

Upvotes: 0

Views: 274

Answers (3)

MatBuompy
MatBuompy

Reputation: 2093

I managed to fix it. First off, if you are on iOS 17+ you need to use a NavigationStack instead of the soon to be deprecated NavigationView since it was the latter causing issues. Otherwise, you can use the NavigationView that I tested on iOS 15.5 and works fine in this scenario. Here's the code:

struct ContentView: View {
    
    @State var selection: Int = 1
    
    var body: some View {
        if #available(iOS 16, *) {
            NavigationStack {
                TabViewNavigation()
            }
        } else {
            NavigationView {
                TabViewNavigation()
            }
        }
    }
    
    @ViewBuilder
    func TabViewNavigation() -> some View {
        TabView(selection: $selection) {
            ListView()
                .tabItem {
                    Label("list view", systemImage: "face.smiling")
                }
                .tag(1)
            Text("list 2 content").tabItem {
                Label("text", systemImage: "face.smiling")
            }
            .tag(2)
        }
    }
}

I'd suggest you to also keep track of the current selected tab using the selection property in the TabView constructor like I did above. Then, in MyView, do not use the onDismiss, rather use the isShowing sheet State variable to show or hide the sheet this way:

struct MyView: View {
    @State private var isShowingSheet = false
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        Button(action: {
            isShowingSheet.toggle()
        }) {
            Text("Show Sheet")
        }
        .sheet(isPresented: $isShowingSheet, onDismiss: {
            isShowingSheet = false
        })
        {
            VStack {
                Text("License Agreement")
                    .font(.title)
                    .padding(50)
                Text("""
                    Terms and conditions go here.
                """)
                .padding(50)
                Button("Dismiss", action: {
                    isShowingSheet = false
                })
            }
        }
    }
    
    func didDismiss() {
        presentationMode.wrappedValue.dismiss()
    }
}

Hope I was able to help you. Let me know if that worked for you!

Upvotes: 0

Arunachalam G
Arunachalam G

Reputation: 1

For this case, you can eliminate the use of @Environment(.presentationMode) var presentationMode and utilize the isShowingSheet variable itself for sheet presentation and dismissal. Update the code from:

.sheet(isPresented: $isShowingSheet, onDismiss: didDismiss)

to:

.sheet(isPresented: $isShowingSheet)

Additionally, replace NavigationView with NavigationStack.

Upvotes: 0

Benzy Neez
Benzy Neez

Reputation: 21730

It works for me if you re-organise the hierarchy as suggested in the comments and put the NavigationView inside the TabView, instead of vice versa.

After the sheet is dismissed, MyView can be seen again. However, it immediately navigates back to ListView due to the .onDismiss parameter to the .sheet modifier. So if you don't want it to navigate back (perhaps for testing), remove the .onDismiss parameter, or comment out the body of didDismiss:

struct ContentView: View {
    var body: some View {
        TabView {
            NavigationView {
                ListView()
            }
            .tabItem {
                Label("list view", systemImage: "face.smiling")
            }
            Text(
                "list 2 content"
            )
            .tabItem {
                Label("text", systemImage: "face.smiling")
            }
        }
    }
}

struct ListView: View {
    var body: some View {
        VStack {
            Text("ListView").font(.largeTitle)
            ScrollView(.vertical, showsIndicators: false) {
                LazyHStack(alignment: .top) {
                    LazyVStack {
                        NavigationLink(destination: MyView()) {
                            Text("Go to MyView")
                        }
                    }
                }
            }
        }
    }
}

struct MyView: View {
    @State private var isShowingSheet = false
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        VStack {
            Text("MyView").font(.largeTitle)
            Spacer()
            Button("Show Sheet") { isShowingSheet.toggle() }
            Spacer()
        }
        .sheet(isPresented: $isShowingSheet, onDismiss: didDismiss) {
            VStack {
                Text("License Agreement")
                    .font(.title)
                    .padding(50)
                Text("""
                Terms and conditions go here.
            """)
                .padding(50)
                Button("Dismiss") { isShowingSheet.toggle() }
            }
        }
    }

    func didDismiss() {
        // Don't navigate back
        // presentationMode.wrappedValue.dismiss()
    }
}

Upvotes: 0

Related Questions