William Tong
William Tong

Reputation: 475

SwiftUI, weird NavigationLink behavior when working with actionSheet

I want to detect if the user meets the prerequisite first before I let him/her in. If the prerequisite is not met, the app will pop an actionSheet and show the user some ways to unlock the feature. It works perfectly fine when I tap on the text. But when I tap on the blank place on the list. It just skip the Binding. And the weird thing is that in my actually project, the Binding becomes "true" even if I only set it to false. Here's the question. Am I using the correct approach or did I miss anything? Or is this a bug? Thank you.

struct ContentView: View {
    @State var linkOne = false
    @State var linkTwo = false
    @State var linkThree = false
    @State var actionOne = false
    @State var actionTwo = false
    @State var actionThree = false
    var body: some View {
        NavigationView{
            List{
                        NavigationLink("Destination View One", destination: DestOneView(), isActive: self.$linkOne)
                            .actionSheet(isPresented: self.$actionOne) { () -> ActionSheet in
                                ActionSheet(title: Text("Hello"), message:Text("This is weird"), buttons: [ActionSheet.Button.cancel()])
                        }.onTapGesture {
                            self.actionOne = true
//                            self.linkOne = true
                        }
                        NavigationLink("Destination View Two", destination: DestTwoView(), isActive: self.$linkTwo)
                        .actionSheet(isPresented: self.$actionTwo) { () -> ActionSheet in
                        ActionSheet(title: Text("Hello"), message:Text("This is weird"), buttons: [ActionSheet.Button.cancel()])
                        }
                        .onTapGesture {
                            self.actionTwo = true
//                            self.linkTwo = true
                        }
                        NavigationLink("Destination View Three", destination: DestThreeView(), isActive: self.$linkThree)
                        .actionSheet(isPresented: self.$actionThree) { () -> ActionSheet in
                        ActionSheet(title: Text("Hello"), message:Text("This is weird"), buttons: [ActionSheet.Button.cancel()])
                        }
                        .onTapGesture {
                            self.actionThree = true
//                            self.linkThree = true
                        }
                    }
        }

    }
}

Three other views.

struct DestOneView: View {
    var body: some View {
        Text("First View")
    }
}

struct DestTwoView: View {
    var body: some View {
        Text("Second View")
    }
}

struct DestThreeView: View {
    var body: some View {
        Text("Third View")
    }
}

Upvotes: 0

Views: 368

Answers (2)

William Tong
William Tong

Reputation: 475

When I came back and tested my the code. The solution didn't really work. May be because of the List's bug. People on another post said that the List in the new view only show once if the sheet is inside the List. So I only got an empty List in the new view when I tap the button in Xcode Version 11.5. For some reasion, if I use NavigationView, all contents are shrunk into the middle of the view instead of aligning to the top.

My work around is to set the Binding in .onAppear. It pops the actionSheet when the view loads. And then use the presentationMode method to return to the previous view.

@Environment(\.presentationMode) var presentationMode
.
.
.
ActionSheet.Button.default(Text("Dismiss"), action: {
          self.presentationMode.wrappedValue.dismiss()}

Upvotes: 0

pawello2222
pawello2222

Reputation: 54466

Generally overriding gestures does not work well within the List. One of the solutions can be to use a Button to present a NavigationLink:

import SwiftUI

struct ContentView: View {
    @State private var linkOne = false
    ...

    var body: some View {
        NavigationView {
            List {
                NavigationLink(destination: SomeView(), isActive: $linkOne) {
                    EmptyView() 
                }

                Button(action: {
                    // here you can perform actions
                    self.linkOne = true
                }, label: {
                    Text("Some text!")
                })

                Spacer()
            }
        }
    }
}

Upvotes: 2

Related Questions