[英]How does $ work in SwiftUI and why can I cast a @StateObject to an @ObservedObject
我是一個開發應用程序的新手,它基本上有一個冰箱 class,里面有食物。 我正在嘗試使用一個帶有食物清單的冰箱。 所以我將foodList設置為已發布的 object 並在程序啟動時實例化一個 @StateObject 冰箱。 基本上,從我的角度來看,每當foodList發生變化時,冰箱 object 都會保存它的 state 並給我一個新的視圖。
另外,我想將此@StateObject 冰箱傳遞給另一個視圖,以便我的另一個視圖可以修改冰箱中的foodList
下面是我的代碼
struct ContentView: View {
@StateObject private var fridge=Fridge();
private var dbStartWith=0;
@State private var selection = 1;
@State private var addFood = false;
var body: some View {
TabView(selection: $selection) {
NavigationView {
List(fridge.container!){
food in NavigationLink(destination: FoodView()) {
Text("HI")
}
}.navigationBarTitle(Text("Fridge Items"), displayMode: .inline)
.navigationBarItems(trailing:
NavigationLink(destination: AddFoodView(fridgeView: fridge)) {
Image(systemName: "plus.circle").resizable().frame(width: 22, height: 22)
} )
}
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
.tag(1)
Text("random tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "bookmark.circle.fill")
Text("profile")
}
.tag(0)
}
}
}
struct FoodView: View{
var body: some View{
NavigationView{
Text("food destination view ");
}
}
}
struct AddFoodView: View{
@ObservedObject var fridgeView: Fridge;
@State private var name = ""
@State private var count : String = "1"
@State private var category : String = "肉類";
@State var showCategory = false
@State var showCount = false
var body: some View{
ZStack{
NavigationView{
Form{
HStack{
Text("食品")
TextField("請輸入材料名", text: $name);
}.padding(.bottom,10).padding(.top,10).padding(.leading,10).padding(.trailing,10)
HStack{
Text("數量")
TextField("請選擇數量",text:$count,onEditingChanged:{(changed) in
self.hideKeyboard();
self.showCount=changed;
}){}
}.padding(.bottom,10).padding(.top,10).padding(.leading,10).padding(.trailing,10)
HStack{
Text("種類")
TextField("請選擇種類",text: $category,onEditingChanged:{(changed) in
self.hideKeyboard();
self.showCategory=changed;
}){}
}.padding(.bottom,10).padding(.top,10).padding(.leading,10).padding(.trailing,10)
}
}.navigationBarItems(trailing: NavigationLink(destination: FoodView()){
Text("保存").foregroundColor(Color.blue).font(.system(size: 18,design: .default))
}).simultaneousGesture(TapGesture().onEnded{
var tempFood=Food(id: fridgeView);//not completed yet
})
ZStack{
if self.showCount{
Rectangle().fill(Color.gray)
.opacity(0.5)
VStack(){
Spacer(minLength: 0);
HStack{
Spacer()
Button(action: {
self.showCount=false;
}, label: {
Text("Done")
}).frame(alignment: .trailing).offset(x:-15,y:15)
}
Picker(selection: $count,label: EmptyView()) {
ForEach(1..<100){ number in
Text("\(number)").tag("\(number)")
}
}.labelsHidden()
} .frame(minWidth: 300, idealWidth: 300, maxWidth: 300, minHeight: 250, idealHeight: 100, maxHeight: 250, alignment: .top).fixedSize(horizontal: true, vertical: true)
.background(RoundedRectangle(cornerRadius: 27).fill(Color.white.opacity(1)))
.overlay(RoundedRectangle(cornerRadius: 27).stroke(Color.black, lineWidth: 1))
.offset(x:10,y:-10)
Spacer()
}
if self.showCategory{
let categoryArr = ["肉類","蔬菜類","飲料類","調味品類"]
ZStack{
Rectangle().fill(Color.gray)
.opacity(0.5)
VStack(){
Spacer(minLength: 0);
HStack{
Spacer()
Button(action: {
self.showCategory=false;
}, label: {
Text("Done")
}).frame(alignment: .trailing).offset(x:-15,y:15)
}
Picker(selection: $category,label: EmptyView()) {
ForEach(0..<categoryArr.count){ number in
Text(categoryArr[number]).tag(categoryArr[number])
}
}.labelsHidden()
} .frame(minWidth: 300, idealWidth: 300, maxWidth: 300, minHeight: 250, idealHeight: 100, maxHeight: 250, alignment: .top).fixedSize(horizontal: true, vertical: true)
.background(RoundedRectangle(cornerRadius: 27).fill(Color.white.opacity(1)))
.overlay(RoundedRectangle(cornerRadius: 27).stroke(Color.black, lineWidth: 1))
Spacer()
}.offset(x:10,y:20)
}
}
}.animation(.easeInOut)
}
}
基本上我想將@StateObject private var fridge
傳遞給struct AddFoodView: View
以便我的AddFoodView
可以使用該變量。 根據我在網上學到的知識,我認為我需要像這樣注入@ObservedObjects
NavigationLink(destination: AddFoodView(fridgeView: fridge))
。 這不會給我帶來讓我困惑的錯誤(至少在調試器階段)。 fridge
不是Food
變量,冰箱fridgeView
不是@ObservedObject Food
變量嗎?
如果我做這樣的事情AddFoodView(fridgeView: $fridge))
。 錯誤Cannot convert value '$fridge' of type 'ObservedObject<Fridge>.Wrapper' to expected type 'Fridge', use wrapped value instead
@StateObject
和@ObservedObject
是事實的來源,它們彼此非常相似並且幾乎可以互換。
要與其他View
共享這些,您應該使用.environmentObject(fridge)
將其傳遞給AddFoodView
並更改@ObservedObject var fridgeView: Fridge;
在AddFoodView
到@EnvironmentObject var fridgeView: Fridge
。
查找有關“在您的應用程序中管理 Model 數據”的 Apple 文檔。
struct BookReader: App {
@StateObject var library = Library()
var body: some Scene {
WindowGroup {
LibraryView()
.environmentObject(library)
}
}
}
struct LibraryView: View {
@EnvironmentObject var library: Library
// ...
}
另一個很好的來源是 Apple SwiftUI 教程,尤其是“處理用戶輸入”
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.