簡體   English   中英

$ 如何在 SwiftUI 中工作,為什么我可以將 @StateObject 轉換為 @ObservedObject

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM