【问题标题】:SwiftUI- passing @State variables to multiple views troubleSwiftUI-将@State变量传递给多个视图麻烦
【发布时间】:2021-09-14 19:52:00
【问题描述】:

我正在尝试在 UI 方面制作一个类似于 iphone 提醒应用程序的应用程序。我有一个视图,其中有一个可以从中添加和删除项目的列表,我还有一个用于添加项目的视图,该视图允许我命名项目并选择一些选项,并且我有另一个视图,当项目在列表被选中,我希望能够显示我所做的名称和选项,但它不显示。 列表视图的代码

struct DotView: View {

enum ActiveSheet: String, Identifiable {
    case SwiftUIView, EditView
    var id: String {
        return self.rawValue
    }
}

@EnvironmentObject var listViewModel: ListViewModel
@AppStorage("dotApiKey") var selectedDotApi: String = ""
@State var dotName:String = ""
@State var dotNumber:String = ""
@State var selection:String = ""
@State var triggerSelection:String = ""
@State var searchText:String = ""
@State var plugUsername:String = ""
@State var plugPassword:String = ""
@State var toggleNotification:Bool
@State var activeSheet : ActiveSheet? = nil
    
@Binding var show : Bool

var body: some View {
        ZStack{
            HStack {
                EditButton()
                    .padding(.leading)
                Spacer()
                Button(action: {
                    self.activeSheet = .SwiftUIView
                }, label: {
                    Text("Add")
                })
                    .padding(.trailing)
            }

            ZStack {
                List {
                    ForEach(listViewModel.dotitems, id:\.dotId){ dotitem in
                        Button(action: { self.activeSheet = .EditView }, label: {
                            DotItemListView(dotitem: dotitem)
                        })
                    }
                    .onDelete(perform: listViewModel.deleteItem)
                    .onMove(perform: listViewModel.moveItem)
                    .listRowBackground(Color("textBG"))
                    
                }.listStyle(PlainListStyle())
                .background(Color("textBG"))
                .frame(height: 300)
                .cornerRadius(10)
                .padding(.horizontal)                    
           }
       }
   .sheet(item: $activeSheet){ sheet in
        switch sheet {
        case .SwiftUIView:
            SwiftUIView(dotName: dotName, dotNumber: dotNumber, selection: selection, triggerSelection: triggerSelection, searchText: searchText, plugUsername: plugUsername, plugPassword: plugPassword, show: $show)
        case .EditView:
            EditView(show:$show)
        }
    }

当我将一个项目添加到列表中时,它会在每一行中显示它

struct DotItemListView:View {
let dotitem: DotItem

var body: some View{
    HStack {
        Text(dotitem.dotName)
        Spacer()
        Text(dotitem.selection)
        Spacer()
        Text(dotitem.dotNumber)
        Spacer()
    }
}

}

这就是我将每个项目添加到列表中的方式

struct DotItem:Equatable, Codable{
var dotId = UUID().uuidString
let dotName:String
let dotNumber:String
let selection:String
}

class ListViewModel: ObservableObject {

@Published var dotitems: [DotItem] = [] {
    didSet {
        saveItem()
    }
}
let dotitemsKey: String = "dotitems_list"

init() {
    getDotItems()
}

func getDotItems() {
    guard
        let data = UserDefaults.standard.data(forKey: dotitemsKey),
        let savedDotItems = try? JSONDecoder().decode([DotItem].self, from: data)
    else { return }
    
    self.dotitems = savedDotItems
}

func deleteItem(indexSet: IndexSet){
    dotitems.remove(atOffsets: indexSet)
}

func moveItem(from: IndexSet, to: Int){
    dotitems.move(fromOffsets: from, toOffset: to)
}

func addItem(dotName: String, dotNumber: String, selection: String){
    let newItem = DotItem(dotName: dotName, dotNumber: dotNumber, selection: selection)
    dotitems.append(newItem)
    
    print(newItem)
}

func saveItem() {
    if let encodedData = try? JSONEncoder().encode(dotitems) {
        UserDefaults.standard.set(encodedData, forKey: dotitemsKey)
    }
}
}

这是我为每个项目输入数据的视图

struct SwiftUIView: View {

@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var listViewModel: ListViewModel
@AppStorage("dotApiKey") var selectedDotApi: String = ""
@State var dotName:String
@State var dotNumber:String
@State var selection:String
@State var triggerSelection:String
@State var selectedColor = Color.black
@State var searchText:String
@State var plugUsername:String
@State var plugPassword:String
@ObservedObject var vm = getDeviceNames()
@State var triggerDot:Bool = false
@State var toggleOnOff:Bool = false
@State var toggleLightColor:Bool = false
@State var isSearching:Bool = false

@StateObject var camera = CameraModel()

@Binding var show : Bool

var body: some View {
    NavigationView {
                    Form {
                        Section(header: Text("Info")) {
                            TextField("Name", text: $dotName)
                            TextField("Number", text: $dotNumber)
                            Picker(selection: $selection, label: Text("Discover Plug")) {
                                ForEach(vm.dataSet, id:\.self) { item in
                                    Text(item.Device).tag(item.Device)
                                }
                            }
                            Toggle(isOn: $isSearching, label: {
                                Text("Have smart plugs?")
                            })
                            if isSearching {
                                HStack{
                                    Text("Casa")
                                    Spacer()
                                    Button(action: {sendPlugDict()}, label: {
                                        Text("Login")
                                    })
                                }
                                TextField("Username", text: $plugUsername)
                                TextField("Password", text: $plugPassword)
                                
                            }
                        }
                        Section {
                            Toggle(isOn: $toggleOnOff, label: {
                                Text("On/Off")
                            })
                        }
                        Section {
                            Toggle(isOn: $toggleLightColor, label: {
                                Text("Light Color")
                            })
                            if toggleLightColor {
                                ColorPicker("Choose Light Color", selection: $selectedColor)
                            }
                        }
                        Section {
                            if listViewModel.dotitems.isEmpty == false {
                                Toggle(isOn: $triggerDot, label: {
                                    Text("Add a DOT to trigger")
                                })
                                if triggerDot {
                                    Picker(selection: $triggerSelection, label: Text("Select DOT")) {
                                        ForEach(listViewModel.dotitems, id:\.dotId){ dotitem in
                                            DotItemListView(dotitem: dotitem)
                                        }
                                    }
                                }
                            }
                        }
                    }
                    .navigationBarTitle("")
                    .navigationBarHidden(true)
                }
}
}

这是我在选择任何列表项时尝试显示数据的视图,除了少数地方外,与上面基本相同

struct EditView: View {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var listViewModel: ListViewModel
@ObservedObject var vm = getDeviceNames()
@State var dataSet = [Result]()
@State var dotName:String = ""
@State var dotNumber:String = ""
@State var selection:String = ""
@State var triggerSelection:String = ""
@State var selectedColor = Color.black
@State var searchText:String = ""
@State var plugUsername:String = ""
@State var plugPassword:String = ""
@State var triggerDot:Bool = false
@State var toggleOnOff:Bool = false
@State var toggleLightColor:Bool = false
@State var isSearching:Bool = false

@Binding var show : Bool

var body: some View {
    NavigationView {
                    Form {
                        Section(header: Text("Info")) { 
                            TextField(dotName, text: $dotName)
                            TextField(dotNumber, text: $dotNumber)
                            Picker(selection: $selection, label: Text("Discorver Plug")) {
                                ForEach(dataSet, id:\.self) { item in
                                    Text(item.Device).tag(item.Device)
                                }
                            }
                            Toggle(isOn: $isSearching, label: {
                                Text("Have smart plugs?")
                            })
                            if isSearching {
                                HStack{
                                    Text("Casa")
                                    Spacer()
                                    Button(action: {
                                            SwiftUIView(dotName: dotName, dotNumber: dotNumber, selection: selection, triggerSelection: triggerSelection, searchText: searchText, plugUsername: plugUsername, plugPassword: plugPassword, show: $show).sendPlugDict()}, label: {
                                        Text("Login")
                                    })
                                }
                                TextField("Username", text: $plugUsername)
                                TextField("Password", text: $plugPassword)
                                
                            }
                        }
                        Section {
                            Toggle(isOn: $toggleOnOff, label: {
                                Text("On/Off")
                            })
                        }
                        Section {
                            Toggle(isOn: $toggleLightColor, label: {
                                Text("Light Color")
                            })
                            if toggleLightColor {
                                ColorPicker("Choose Light Color", selection: $selectedColor)
                            }
                        }
                        Section {
                            if listViewModel.dotitems.isEmpty == false {
                                Toggle(isOn: $triggerDot, label: {
                                    Text("Add a DOT to trigger")
                                })
                                if triggerDot {
                                    Picker(selection: $triggerSelection, label: Text("Select DOT")) {
                                        ForEach(listViewModel.dotitems, id:\.dotId){ dotitem in
                                            DotItemListView(dotitem: dotitem)
                                        }
                                    }
                                }
                            }
                        }
                    }
                    .navigationBarTitle("")
                    .navigationBarHidden(true)
                }

}
}

我知道这有很多事情要做,但我们将不胜感激任何帮助

【问题讨论】:

标签: list foreach swiftui state swiftui-list


【解决方案1】:

在您想要将状态传递给的视图上使用@Binding。

视图1:

@State var a = true 

View2(a: $a)

视图2:

@Binding var a : Bool

要在全局范围内传递数据,请使用 @EnvoirmentObject :

示例:

@main
struct YourApp: App {

    @StateObject var session = Session()
    
    var body: some Scene {
        WindowGroup {
            SplashView()
                .environmentObject(session)
        }
    }
}

会话:

class Session: ObservableObject {

    /// user signin state
    @Published  var isSignedIn : Bool = false
}

视图1,视图2,视图3 ....:

struct SplashView: View {
    
    @EnvironmentObject var session : Session
    
    var body: some View {
        VStack{
            SignInView()
                .opacity(session.isSignedIn ? 0:1)
        }
        .background(Color.background.ignoresSafeArea())
    }
}

【讨论】:

  • 我将如何使用 3 个视图执行此操作?因为如果我在创建项目的视图上执行您的View1 示例,并在显示项目数据的视图上使用您的View2 示例,它会让我在显示它的第三个视图上使用@State var该列表是因为在您的 View1 示例中,您的 View2(a: $a) 与您的 @State var 视图相同,但我的视图不同
  • 基本上我是这样设置的- View1 @State var a: Bool, View2 @Binding var a: Bool, View3 @987654334 @ 但它没有用。如果我在View1View2 中都使用@Binding,当我选择一个列表项时,它会显示在View3 中,但是当我添加另一个项目时,它会显示数据并且它不应该显示
  • 应该是这样的:State -> Binding -> Binding -> ....
  • 但是在其中一个绑定视图中我调用了状态视图,这使我将参数更深入地放入我的应用程序中
  • 在我编辑答案时使用 EnvironmentObject
猜你喜欢
  • 2011-09-30
  • 2011-10-01
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多