Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
405 views
in Technique[技术] by (71.8m points)

SwiftUI: How can I navigate to a NavigationLink when there is a Picker on the same Form?

I want to put a "Scan" button on the same Form row as my Picker. The scanner View has its own NavigationLink that should pop up when the user taps the Scan button.

What actually happens:

Both the Picker's NavigationLink and the Scanner's NavigationLink destination views appear at the same time. When you tap either the Picker or the Scan button, you will randomly see one of the two destinations (assuming one is above the other in z-order).

Here is what it will look like:

enter image description here

Here is the code to reproduce this issue...

    struct Truck: Hashable, Identifiable {
        var id: String
        var color: String
        var assetId: String
    }
    
    
    struct ContentView: View
    {
        var trucks = [
            Truck(id: "a", color: "Red", assetId: "1"),
            Truck(id: "b", color: "Green", assetId: "2"),
            Truck(id: "c", color: "Blue", assetId: "3")
        ]
        @State private var myTruck: Truck?
        
        var body: some View {
            GeometryReader { geometry in
                NavigationView {
                    Form {
                        HStack {
                            Picker("Choose a truck", selection: $myTruck) {
                                ForEach(trucks) { truck in
                                    Text(truck.color).tag(Optional.some(truck.self))
                                }
                            }
                            .frame(maxWidth: (geometry.size.width * 0.5))
                            .clipped()
                            Scanner(callback: { barcode in
                                myTruck = trucks.filter { $0.assetId == barcode }.first
                            })
                        }
                    }
                }
            }
        }
    }
    
    
    struct Scanner: View {
        @State private var isShowingScanner: Bool = false
        var callback: (String)->()
        var body: some View {
            ZStack { // makes NavigationLink not visible.
                NavigationLink(destination: Button("Scan 3 example", action: {
                    callback("3")
                    self.isShowingScanner = false
                }), isActive: $isShowingScanner) {
                    EmptyView()
                }
                .frame(width: 0, height: 0)
                Button("Scan", action: {
                    isShowingScanner = true
                })
            }
        }
    }

What I want to happen is if you tap the picker the list of options appears. If you tap the scan button the scanner window should appear. I thought about using tags for the various destination views, but I don't know how to do that on the Picker's destination. Also, the scanner is a separate component, so I thought it would be able to control its own NavigationLink.

XCode 12.3 Swift 5 iOS 14.3

question from:https://stackoverflow.com/questions/65836170/swiftui-how-can-i-navigate-to-a-navigationlink-when-there-is-a-picker-on-the-sa

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The solution is actually pretty simple. The picker needs to be put in a frame that is less than the width of the row, and then clipped. Otherwise, it will be selectable in the entire row. I usually use a GeometryReader to get the proportions correct for each device. Your row would look like this assuming a GeometryReader declared with a proxy named geometry:

HStack {
    Picker("Choose a truck", selection: $myTruck) {
        ForEach(trucks) { truck in
             Text(truck.color).tag(Optional.some(truck.self))
        }
    }
    .frame(width: (geometry.size.width * 0.5)) // uses 50% of the row. You can
                                               // make it any size you want.
    .clipped()

    Scanner(callback: { barcode in
        myTruck = trucks.filter { $0.assetId == barcode }.first
    })
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...