SwiftUI中选择器和窗体的奇怪行为

SwiftUI中选择器和窗体的奇怪行为,swiftui,swiftui-form,Swiftui,Swiftui Form,我正在SwiftUI中开发一个应用程序来管理一个虚拟数据中心(服务器、防火墙规则、负载平衡器等)。我附上的代码是该应用程序的摘录,以显示我目前面临的问题,而我自己无法解决。 问题(或SwiftUI bug?)如下: a) 我不能在选择器中选择一个值两次 b) 当我试图在表单中隐藏某些字段时,会出现奇怪的行为 使用所附代码复制此问题的方法如下: 运行应用程序 转到“创建”选项卡 单击防火墙策略以创建新的防火墙策略 单击选择器协议并更改值(例如UDP) 再次尝试更改该值(例如TCP)。然后,问题

我正在SwiftUI中开发一个应用程序来管理一个虚拟数据中心(服务器、防火墙规则、负载平衡器等)。我附上的代码是该应用程序的摘录,以显示我目前面临的问题,而我自己无法解决。 问题(或SwiftUI bug?)如下:

  • a) 我不能在选择器中选择一个值两次
  • b) 当我试图在表单中隐藏某些字段时,会出现奇怪的行为
使用所附代码复制此问题的方法如下:

  • 运行应用程序
  • 转到“创建”选项卡
  • 单击防火墙策略以创建新的防火墙策略
  • 单击选择器协议并更改值(例如UDP)
  • 再次尝试更改该值(例如TCP)。然后,问题a)出现。选择器显示为“已选定”,但不起作用
  • 转到picker操作并将value更改为Deny,然后表单中的某些行被隐藏(预期行为)
  • 现在,再次尝试更改选择器操作以允许,然后b)出现问题,我得到一个奇怪的视图更改和一个空白屏幕
  • 我在MacOS 10.15.2上运行Xcode 11.3。欢迎任何帮助或提示

    import SwiftUI
    
    struct ContentView: View {
        @State var selectedTab = 1
        var body: some View {
            TabView(selection: $selectedTab){
                CreateView(selectedTab: $selectedTab)
                    .tabItem {
                        Image(systemName: "plus")
                        Text("Create")
                    }.tag(0)
                ListView()
                    .tabItem {
                        Image(systemName: "cloud")
                        Text("List")
                    }.tag(1)
            }
        }
    }
    
    
    struct CreateView: View {
        @Binding var selectedTab: Int
        var body: some View {
            VStack{
                NavigationView{
                    List{
                        Text("Server")
                        NavigationLink(destination: CreateFirewallPolicyView(selectedTab: $selectedTab)){
                            Text("Firewall Policy")
                        }
                    }
                    .navigationBarTitle("Select the element you want to create", displayMode: .inline)
               }
            }
        }
    }
    
    struct ListView: View {
        var body: some View {
            NavigationView{
                List{
                    Section(header: Text("Servers")){
                        Text("Server 1")
                        Text("Server 2")
                    }
                    Section(header: Text("Firewall policies")){
                        Text("Firewall 1")
                        Text("Firewall 2")
                    }
                }
                .navigationBarTitle("My virtual datacenter", displayMode: .large)
            }
        }
    }
    
    
    
    struct CreateFirewallPolicyView: View {
        @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    
        @Binding var selectedTab: Int
    
        @State private var name: String = ""
        @State private var allowed_ip: String = ""
        @State private var ports: String = ""
        @State private var description: String = ""
        @State private var selectedAction = RuleAction.allow
        @State private var selectedProtocol = NetworkProtocol.tcp
        @State private var rules: [Rule] = []
    
        var body: some View {
            Form {
                Section(header: Text("Name of the firewall policy")){
                    TextField("Nombre", text: $name)
                }
                Section(header: Text("New rule")){
                    Picker(selection: $selectedAction, label: Text("Action")) {
                        ForEach(RuleAction.allCases, id:\.self) { fw_action in
                            Text(fw_action.name)
                        }
                    }
                    if (selectedAction == RuleAction.allow){
                        TextField("Allowed IP", text: $allowed_ip)
                        Picker(selection: $selectedProtocol, label: Text("Protocol")) {
                            ForEach(NetworkProtocol.allCases, id:\.self) { fw_protocol in
                                Text(fw_protocol.name)
                            }
                        }
                        TextField("Ports", text: $ports)
                    }
                    TextField("Description", text: $description)
                    Button(action: {
                        if self.selectedAction == RuleAction.deny{
                            self.ports = ""
                            self.allowed_ip = ""
                            self.selectedProtocol = NetworkProtocol.any
                        }
                        self.rules.append(Rule(id: UUID().uuidString, protocol: self.selectedProtocol, port: (self.ports.isEmpty ? nil : self.ports), source: (self.allowed_ip.isEmpty ? "0.0.0.0" : self.allowed_ip), description: (self.description.isEmpty ? nil : self.description), action: self.selectedAction))
                        self.allowed_ip = ""
                        self.ports = ""
                        self.description = ""
                        self.selectedAction = RuleAction.allow
                        self.selectedProtocol = NetworkProtocol.tcp
                    }) {
                        HStack{
                            Spacer()
                            Text("Add new rule")
                        }.disabled(self.selectedAction == RuleAction.allow && (self.selectedProtocol == NetworkProtocol.tcp || self.selectedProtocol == NetworkProtocol.udp || self.selectedProtocol == NetworkProtocol.tcp_udp) && self.ports.isEmpty)
    
                    }
                }
                Section(header: Text("Rules to add")){
                    ForEach(self.rules, id:\.self) { rule in
                        Text("\(rule.action.rawValue.capitalized) - \(rule.source ?? "all") - \(rule.protocol.rawValue) - \(rule.port ?? "")")
                    }.onDelete(perform: delete)
                }
    
            }
            .navigationBarTitle("Create Firewall Policy")
            .navigationBarBackButtonHidden(true)
            .navigationBarItems(
                leading:
                    Button(action: {
                        self.presentationMode.wrappedValue.dismiss()
                    }) {
                        Text("Cancel")
                    },
                trailing:
                    Button(action: {
                        print("Create")
                    }) {
                        Text("Create")
                    }
                    .disabled(name.isEmpty || rules.count == 0)
            )
        }
    
        func delete(at offsets: IndexSet) {
            rules.remove(atOffsets: offsets)
        }
    }
    
    struct Rule:Codable, Hashable, Identifiable{
        let id: String
        var `protocol`: NetworkProtocol
        var port: String?
        var portFrom: Int?
        var portTo: Int?
        var source: String?
        var description: String?
        var action: RuleAction
    }
    
    enum NetworkProtocol: String, Codable, Hashable, CaseIterable{
        case tcp = "TCP"
        case udp = "UDP"
        case icmp = "ICMP"
        case tcp_udp = "TCP/UDP"
        case ipsec = "IPSEC"
        case gre = "GRE"
        case any = "ANY"
        var name: String {
            return "\(self.rawValue)"
        }
    }
    
    enum RuleAction: String, Codable, Hashable, CaseIterable{
        case allow
        case deny
        var name: String {
            return "\(self)".capitalized
        }
    }
    
    导入快捷界面
    结构ContentView:View{
    @状态变量selectedTab=1
    var body:一些观点{
    选项卡视图(选择:$selectedTab){
    CreateView(selectedTab:$selectedTab)
    .tabItem{
    图像(系统名称:“plus”)
    文本(“创建”)
    }.tag(0)
    ListView()
    .tabItem{
    图像(系统名:“云”)
    文本(“列表”)
    }.标签(1)
    }
    }
    }
    结构CreateView:View{
    @绑定变量selectedTab:Int
    var body:一些观点{
    VStack{
    导航视图{
    名单{
    文本(“服务器”)
    导航链接(目标:CreateFirewallPolicyView(selectedTab:$selectedTab)){
    文本(“防火墙策略”)
    }
    }
    .navigationBarTitle(“选择要创建的元素”,显示模式:.inline)
    }
    }
    }
    }
    结构列表视图:视图{
    var body:一些观点{
    导航视图{
    名单{
    节(标题:文本(“服务器”)){
    文本(“服务器1”)
    文本(“服务器2”)
    }
    节(标题:文本(“防火墙策略”)){
    文本(“防火墙1”)
    文本(“防火墙2”)
    }
    }
    .navigationBarTitle(“我的虚拟数据中心”,显示模式:。大)
    }
    }
    }
    结构CreateFirewallPolicyView:视图{
    @环境(\.presentationMode)变量presentationMode:绑定
    @绑定变量selectedTab:Int
    @国家私有变量名称:String=“”
    @允许的状态私有变量\u ip:String=“”
    @状态专用变量端口:String=“”
    @国家私有变量说明:String=“”
    @状态私有变量selectedAction=RuleAction.allow
    @状态专用变量selectedProtocol=NetworkProtocol.tcp
    @国家私有var规则:[规则]=[]
    var body:一些观点{
    形式{
    节(标题:文本(“防火墙策略的名称”)){
    TextField(“Nombre”,text:$name)
    }
    节(标题:文本(“新规则”)){
    选择器(选择:$selectedAction,标签:文本(“操作”)){
    ForEach(RuleAction.allCases,id:\.self){fw\u中的操作
    文本(fw_action.name)
    }
    }
    if(selectedAction==RuleAction.allow){
    TextField(“允许的IP”,text:$Allowed\u IP)
    选择器(选择:$selectedProtocol,标签:文本(“协议”)){
    ForEach(NetworkProtocol.allCases,id:\.self){fw\u中的协议
    文本(FWU协议名称)
    }
    }
    TextField(“端口”,text:$Ports)
    }
    TextField(“说明”,text:$Description)
    按钮(操作:{
    如果self.selectedAction==RuleAction.deny{
    self.port=“”
    self.allowed_ip=“”
    self.selectedProtocol=NetworkProtocol.any
    }
    self.rules.append(规则(id:UUID().uuiString,协议:self.selectedProtocol,端口:(self.ports.isEmpty?nil:self.ports.isEmpty?.0.0):self.allowed_ip),描述:(self.description.isEmpty?nil:self.description),操作:self.selectedAction))
    self.allowed_ip=“”
    self.port=“”
    self.description=“”
    self.selectedAction=RuleAction.allow
    self.selectedProtocol=NetworkProtocol.tcp
    }) {
    HStack{
    垫片()
    文本(“添加新规则”)
    }.disabled(self.selectedAction==RuleAction.allow&(self.selectedProtocol==NetworkProtocol.tcp | | | self.selectedProtocol==NetworkProtocol.udp | | self.selectedProtocol==NetworkProtocol.tcp| u udp)&&self.port.isEmpty)
    }
    }
    节(标题:文本(“要添加的规则”)){
    ForEach(self.rules,id:\.self){rule in
    文本(“\(rule.action.rawValue.capitalized)-\(rule.source??“all”)-\(rule.protocol.rawValue)-\(rule.port??”)
    }.onDelete(执行:删除)
    }
    }
    .navigationBarTitle(“创建防火墙策略”)
    .navigationBarBackButtonHidden(真)
    .航海术语(
    领先:
    按钮(操作:{
    self.presentationMode.wrappedValue.discouse()文件
    }) {