SwiftUI-将@State变量传递给多个视图麻烦
Posted
技术标签:
【中文标题】SwiftUI-将@State变量传递给多个视图麻烦【英文标题】:SwiftUI- passing @State variables to multiple views trouble 【发布时间】: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)
我知道这有很多事情要做,但我们将不胜感激任何帮助
【问题讨论】:
你能想出一个minimal reproducible example吗?我怀疑这里有很多内容可以删除,同时仍然可以证明问题。 【参考方案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 @ 但它没有用。如果我在View1
和View2
中都使用@Binding
,当我选择一个列表项时,它会显示在View3
中,但是当我添加另一个项目时,它会显示数据并且它不应该显示
应该是这样的:State -> Binding -> Binding -> ....
但是在其中一个绑定视图中我调用了状态视图,这使我将参数更深入地放入我的应用程序中
在我编辑答案时使用 EnvironmentObject以上是关于SwiftUI-将@State变量传递给多个视图麻烦的主要内容,如果未能解决你的问题,请参考以下文章
通过@State 传递 NSManagedObject ...? SwiftUI
如何将一个 SwiftUI 视图作为变量传递给另一个视图结构
Init State var 来自另一个视图,swiftui [重复]