首页 > 解决方案 > SwiftUI:当同一个表单上有一个 Picker 时,我如何导航到 NavigationLink?

问题描述

我想在与我的选取器相同的表单行上放置一个“扫描”按钮。扫描仪视图有自己的 NavigationLink,当用户点击 Scan 按钮时应该会弹出它。

实际发生的情况:

Picker 的 NavigationLink 和 Scanner 的 NavigationLink 目标视图同时出现。当您点击 Picker 或 Scan 按钮时,您将随机看到两个目的地之一(假设一个在 z 顺序中位于另一个之上)。

这是它的样子:

在此处输入图像描述

这是重现此问题的代码...

    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
                })
            }
        }
    }

我想要发生的是,如果您点击选择器,则会出现选项列表。如果您点击扫描按钮,扫描仪窗口应该会出现。我考虑过为各种目的地视图使用标签,但我不知道如何在 Picker 的目的地上执行此操作。此外,扫描仪是一个单独的组件,所以我认为它可以控制自己的 NavigationLink。

XCode 12.3 斯威夫特 5 iOS 14.3

标签: formsswiftuipickerswiftui-navigationlink

解决方案


解决方案实际上非常简单。选择器需要放在小于行宽的框架中,然后进行裁剪。否则,它将在整行中可选。我通常使用 GeometryReader 来获取每个设备的正确比例。假设使用名为几何的代理声明 GeometryReader,您的行将如下所示:

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
    })
}

推荐阅读