样式为DefaultPickerStyle()的SwiftUI选择器不工作

样式为DefaultPickerStyle()的SwiftUI选择器不工作,swiftui,environmentobject,defaultpickerstyle,menupickerstyle,Swiftui,Environmentobject,Defaultpickerstyle,Menupickerstyle,使用Swift5.2.3、iOS14.4.2、XCode12.4、 在SwiftUI中使用.sheet修饰符一开始让我感到兴奋,因为它似乎是一种显示模式表的简单而有效的方法 然而,在现实世界的应用程序中,.sheet几乎可以集成 以下是发现的两个bug(除其他外…): 错误1:当在图纸的分段选择器中时,具有DefaultPickerStyle的选择器不工作 错误2:工作表不会偶尔关闭() 现在让我们关注Bug Nr1:“当在图纸的分段选择器中时,具有DefaultPickerStyle的选择器不

使用Swift5.2.3、iOS14.4.2、XCode12.4、

在SwiftUI中使用
.sheet
修饰符一开始让我感到兴奋,因为它似乎是一种显示模式表的简单而有效的方法

然而,在现实世界的应用程序中,
.sheet
几乎可以集成

以下是发现的两个bug(除其他外…):

错误1:当在图纸的分段选择器中时,具有DefaultPickerStyle的选择器不工作

错误2:工作表不会偶尔关闭()

现在让我们关注Bug Nr1:“当在图纸的分段选择器中时,具有DefaultPickerStyle的选择器不工作”

我的意思可以在这个例子中看到。这是一个真实世界应用程序的摘录。(是的,我需要放置如此多的视图,因为普通教科书的示例工作得非常好——但一旦变得稍微复杂一点就不行了…)

请注意,“可怕的儿童”实际上是
.pickerStyle(DefaultPickerStyle())
!(您可以在名为
SettingsView
的最底部视图中找到它

如果我用
.pickerStyle(MenuPickerStyle())
替换该样式,那么应用程序运行得非常好

DefaultPickerStyle()
有什么问题

请参见以下两个说明问题的视频:

Video-1:FAULT显示
DefaultPickerStyle()
(您可以看到,
.onChange(of:categoryIndex){(idx)in…}
从未使用此选择器样式调用过…)

视频-2:正确显示
MenuPickerStyle()

ContentView如下所示:

enum THSheetSelection: Hashable, Identifiable {        
    case infoSettings
    var id: THSheetSelection { self }
}

struct ContentView: View {
    
    @State var sheetState: THSheetSelection?
    
    var body: some View {
        VStack {
            Text("Hello, world!")
                .padding()
            Button("Show Settings Sheet") {
                sheetState = .infoSettings
            }
        }
        .sheet(item: $sheetState) { state in
            switch state {
            case .infoSettings:
                InfoSettingsView()
            }
        }
    }
}
struct InfoSettingsView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    @State private var segmentSelection = 0
    @State private var infoShown = false
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                Picker("", selection: $segmentSelection) {
                    Text("Info").tag(0)
                    Text("Settiongs").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle())
                .background(Color.blue)
                .padding()
                
                switch segmentSelection {
                case 0:
                    InfoView()
                case 1:
                    SettingsView()
                default:
                    InfoView()
                }
            }
            .navigationBarTitle("Info & Settings")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }) {
                        Text("Done")
                    }
                }
            }
            .onAppear {
                segmentSelection = 0
            }
        }
    }
}
struct InfoView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    let versionNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String) ?? ""
    let buildNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String) ?? ""
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text("App Info")) {
                    HStack {
                        Text("App Version")
                        Spacer()
                        Text("v\(versionNr) (\(buildNr))")
                    }
                }
            }
            .ignoresSafeArea()
            
            Spacer()
        }
    }
}
struct SettingsView: View {
        
    @State private var categoryIndex = 0
    var categorySelection = ["Choice 1", "Choice 2", "Choice 3", "Choice 4"]
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text(LocalizedStringKey("InterDeviceCommKey"))) {
                    Picker(selection: $categoryIndex, label: Text(LocalizedStringKey("TechChoiceKey"))) {
                        ForEach(0 ..< categorySelection.count, id: \.self) { idx in
                            Text(categorySelection[idx]).tag(idx)
                        }
                    }
                    .pickerStyle(DefaultPickerStyle()) // does NOT behave correctly
                    // .pickerStyle(MenuPickerStyle()) // does behave correctly
                    .onChange(of: categoryIndex) { (idx) in  /// ????????? why this never gets called with DefaultPickerStyle() ?????????
                        print("categoryChanged to index \(idx)")
                    }
                }
                Section(header: Text("Selected Choice")) {
                    HStack {
                        Text("My choice")
                        Spacer()
                        Text("\(categorySelection[categoryIndex])")
                    }
                }
                .ignoresSafeArea()
            }            
            Spacer()
        }
    }
}
信息设置视图如下所示:

enum THSheetSelection: Hashable, Identifiable {        
    case infoSettings
    var id: THSheetSelection { self }
}

struct ContentView: View {
    
    @State var sheetState: THSheetSelection?
    
    var body: some View {
        VStack {
            Text("Hello, world!")
                .padding()
            Button("Show Settings Sheet") {
                sheetState = .infoSettings
            }
        }
        .sheet(item: $sheetState) { state in
            switch state {
            case .infoSettings:
                InfoSettingsView()
            }
        }
    }
}
struct InfoSettingsView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    @State private var segmentSelection = 0
    @State private var infoShown = false
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                Picker("", selection: $segmentSelection) {
                    Text("Info").tag(0)
                    Text("Settiongs").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle())
                .background(Color.blue)
                .padding()
                
                switch segmentSelection {
                case 0:
                    InfoView()
                case 1:
                    SettingsView()
                default:
                    InfoView()
                }
            }
            .navigationBarTitle("Info & Settings")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }) {
                        Text("Done")
                    }
                }
            }
            .onAppear {
                segmentSelection = 0
            }
        }
    }
}
struct InfoView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    let versionNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String) ?? ""
    let buildNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String) ?? ""
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text("App Info")) {
                    HStack {
                        Text("App Version")
                        Spacer()
                        Text("v\(versionNr) (\(buildNr))")
                    }
                }
            }
            .ignoresSafeArea()
            
            Spacer()
        }
    }
}
struct SettingsView: View {
        
    @State private var categoryIndex = 0
    var categorySelection = ["Choice 1", "Choice 2", "Choice 3", "Choice 4"]
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text(LocalizedStringKey("InterDeviceCommKey"))) {
                    Picker(selection: $categoryIndex, label: Text(LocalizedStringKey("TechChoiceKey"))) {
                        ForEach(0 ..< categorySelection.count, id: \.self) { idx in
                            Text(categorySelection[idx]).tag(idx)
                        }
                    }
                    .pickerStyle(DefaultPickerStyle()) // does NOT behave correctly
                    // .pickerStyle(MenuPickerStyle()) // does behave correctly
                    .onChange(of: categoryIndex) { (idx) in  /// ????????? why this never gets called with DefaultPickerStyle() ?????????
                        print("categoryChanged to index \(idx)")
                    }
                }
                Section(header: Text("Selected Choice")) {
                    HStack {
                        Text("My choice")
                        Spacer()
                        Text("\(categorySelection[categoryIndex])")
                    }
                }
                .ignoresSafeArea()
            }            
            Spacer()
        }
    }
}
InfoView如下所示:

enum THSheetSelection: Hashable, Identifiable {        
    case infoSettings
    var id: THSheetSelection { self }
}

struct ContentView: View {
    
    @State var sheetState: THSheetSelection?
    
    var body: some View {
        VStack {
            Text("Hello, world!")
                .padding()
            Button("Show Settings Sheet") {
                sheetState = .infoSettings
            }
        }
        .sheet(item: $sheetState) { state in
            switch state {
            case .infoSettings:
                InfoSettingsView()
            }
        }
    }
}
struct InfoSettingsView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    @State private var segmentSelection = 0
    @State private var infoShown = false
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                Picker("", selection: $segmentSelection) {
                    Text("Info").tag(0)
                    Text("Settiongs").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle())
                .background(Color.blue)
                .padding()
                
                switch segmentSelection {
                case 0:
                    InfoView()
                case 1:
                    SettingsView()
                default:
                    InfoView()
                }
            }
            .navigationBarTitle("Info & Settings")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }) {
                        Text("Done")
                    }
                }
            }
            .onAppear {
                segmentSelection = 0
            }
        }
    }
}
struct InfoView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    let versionNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String) ?? ""
    let buildNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String) ?? ""
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text("App Info")) {
                    HStack {
                        Text("App Version")
                        Spacer()
                        Text("v\(versionNr) (\(buildNr))")
                    }
                }
            }
            .ignoresSafeArea()
            
            Spacer()
        }
    }
}
struct SettingsView: View {
        
    @State private var categoryIndex = 0
    var categorySelection = ["Choice 1", "Choice 2", "Choice 3", "Choice 4"]
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text(LocalizedStringKey("InterDeviceCommKey"))) {
                    Picker(selection: $categoryIndex, label: Text(LocalizedStringKey("TechChoiceKey"))) {
                        ForEach(0 ..< categorySelection.count, id: \.self) { idx in
                            Text(categorySelection[idx]).tag(idx)
                        }
                    }
                    .pickerStyle(DefaultPickerStyle()) // does NOT behave correctly
                    // .pickerStyle(MenuPickerStyle()) // does behave correctly
                    .onChange(of: categoryIndex) { (idx) in  /// ????????? why this never gets called with DefaultPickerStyle() ?????????
                        print("categoryChanged to index \(idx)")
                    }
                }
                Section(header: Text("Selected Choice")) {
                    HStack {
                        Text("My choice")
                        Spacer()
                        Text("\(categorySelection[categoryIndex])")
                    }
                }
                .ignoresSafeArea()
            }            
            Spacer()
        }
    }
}
设置视图如下所示:

enum THSheetSelection: Hashable, Identifiable {        
    case infoSettings
    var id: THSheetSelection { self }
}

struct ContentView: View {
    
    @State var sheetState: THSheetSelection?
    
    var body: some View {
        VStack {
            Text("Hello, world!")
                .padding()
            Button("Show Settings Sheet") {
                sheetState = .infoSettings
            }
        }
        .sheet(item: $sheetState) { state in
            switch state {
            case .infoSettings:
                InfoSettingsView()
            }
        }
    }
}
struct InfoSettingsView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    @State private var segmentSelection = 0
    @State private var infoShown = false
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                Picker("", selection: $segmentSelection) {
                    Text("Info").tag(0)
                    Text("Settiongs").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle())
                .background(Color.blue)
                .padding()
                
                switch segmentSelection {
                case 0:
                    InfoView()
                case 1:
                    SettingsView()
                default:
                    InfoView()
                }
            }
            .navigationBarTitle("Info & Settings")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }) {
                        Text("Done")
                    }
                }
            }
            .onAppear {
                segmentSelection = 0
            }
        }
    }
}
struct InfoView: View {
    
    @Environment(\.presentationMode) var presentationMode
    
    let versionNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String) ?? ""
    let buildNr: String = (Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String) ?? ""
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text("App Info")) {
                    HStack {
                        Text("App Version")
                        Spacer()
                        Text("v\(versionNr) (\(buildNr))")
                    }
                }
            }
            .ignoresSafeArea()
            
            Spacer()
        }
    }
}
struct SettingsView: View {
        
    @State private var categoryIndex = 0
    var categorySelection = ["Choice 1", "Choice 2", "Choice 3", "Choice 4"]
    
    var body: some View {
        
        VStack {
            Form {
                Section(header: Text(LocalizedStringKey("InterDeviceCommKey"))) {
                    Picker(selection: $categoryIndex, label: Text(LocalizedStringKey("TechChoiceKey"))) {
                        ForEach(0 ..< categorySelection.count, id: \.self) { idx in
                            Text(categorySelection[idx]).tag(idx)
                        }
                    }
                    .pickerStyle(DefaultPickerStyle()) // does NOT behave correctly
                    // .pickerStyle(MenuPickerStyle()) // does behave correctly
                    .onChange(of: categoryIndex) { (idx) in  /// ????????? why this never gets called with DefaultPickerStyle() ?????????
                        print("categoryChanged to index \(idx)")
                    }
                }
                Section(header: Text("Selected Choice")) {
                    HStack {
                        Text("My choice")
                        Spacer()
                        Text("\(categorySelection[categoryIndex])")
                    }
                }
                .ignoresSafeArea()
            }            
            Spacer()
        }
    }
}
结构设置视图:视图{ @国家私有变量类别索引=0 变量类别选择=[“选择1”、“选择2”、“选择3”、“选择4”] var body:一些观点{ VStack{ 形式{ 节(标题:文本(LocalizedStringKey(“InterDeviceCommKey”)){ 选择器(选择:$categoryIndex,标签:文本(LocalizedStringKey(“TechChoiceKey”)){ ForEach(0.. 你知道为什么SwiftUI
.sheet
的DefaultPickerStyle()在上述情况下不能正常工作吗