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