SwiftUI- 将@State 变量传递给多个视图有问题
SwiftUI- passing @State variables to multiple views trouble
我正在尝试制作一款类似于 iPhone 提醒应用的应用 UI。我有一个视图,其中有一个列表,我可以从中添加和删除项目,我还有一个视图用于添加一个项目,允许我命名该项目和 select 一些选项,我还有另一个视图何时列表中的一项是 selected,我希望能够显示我所做的名称和选项,但它没有显示。 列表视图的代码
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)
}
}
}
这是我试图在 selected 任何列表项时显示数据的视图,除了少数地方
与上面基本相同
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)
}
}
}
我知道这有很多事情要做,但我们将不胜感激
在要将状态传递给的视图上使用@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())
}
}
我正在尝试制作一款类似于 iPhone 提醒应用的应用 UI。我有一个视图,其中有一个列表,我可以从中添加和删除项目,我还有一个视图用于添加一个项目,允许我命名该项目和 select 一些选项,我还有另一个视图何时列表中的一项是 selected,我希望能够显示我所做的名称和选项,但它没有显示。 列表视图的代码
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)
}
}
}
这是我试图在 selected 任何列表项时显示数据的视图,除了少数地方
与上面基本相同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)
}
}
}
我知道这有很多事情要做,但我们将不胜感激
在要将状态传递给的视图上使用@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())
}
}