将状态变量传递给父视图

Passing a state variable to parent view

我有以下代码:

struct BookView: View {
    
    @State var title = ""
    @State var author = ""

    var body: some View {
        TextField("Title", text: $title)
        TextField("Author", text: $author)
    }
}
struct MainView: View {
    @State private var presentNewBook: Bool = false
    var body: some View {
        NavigationView {
            // ... some button that toggles presentNewBook
        }.sheet(isPresented: $presentNewBook) {
        let view = BookView()
        view.toolbar {
            ToolbarItem(placement: principal) {
                TextField("Title", text: view.$title)
            }
        }
    }
    }
}

这可以编译,但在运行时出现以下错误:

Accessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update.

如何将状态变量传递给其他外部视图?我不能在 BookView 上使用 ObservableObject,因为那需要我将它从 struct 更改为 class

一般来说,您的状态应该始终位于视图层次结构的更高层级。尝试从父级访问子状态是一种反模式。

一种选择是使用 @Bindings 将值传递给子视图:

struct BookView: View {
    
    @Binding var title : String
    @Binding var author : String
    
    var body: some View {
        TextField("Title", text: $title)
        TextField("Author", text: $author)
    }
}

struct ContentView: View {
    @State private var presentNewBook: Bool = false
    
    @State private var title = ""
    @State private var author = ""
    
    var body: some View {
        NavigationView {
            VStack {
                Text("Title: \(title)")
                Text("Author: \(author)")
                Button("Open") {
                    presentNewBook = true
                }
            }
        }.sheet(isPresented: $presentNewBook) {
            BookView(title: $title, author: $author)
        }
    }
}

另一种可能性是使用 ObservableObject:

class BookState : ObservableObject {
    @Published var title = ""
    @Published var author = ""
}

struct BookView: View {
    
    @ObservedObject var bookState : BookState
    
    var body: some View {
        TextField("Title", text: $bookState.title)
        TextField("Author", text: $bookState.author)
    }
}

struct ContentView: View {
    @State private var presentNewBook: Bool = false
    @StateObject private var bookState = BookState()
    
    var body: some View {
        NavigationView {
            VStack {
                Text("Title: \(bookState.title)")
                Text("Author: \(bookState.author)")
                Button("Open") {
                    presentNewBook = true
                }
            }
        }.sheet(isPresented: $presentNewBook) {
            BookView(bookState: bookState)
        }
    }
}

我稍微更改了您的示例视图,因为对我来说结构不清楚,但在父级别拥有状态的概念是重要元素。

您还可以在视图之间传递状态变量:

let view = BookView(title: "foobar")
view.toolbar {
     ToolbarItem(placement: principal) {
         TextField("Title", text: view.$title)
     }
}

然后,在BookView里面:

@State var title: String

init(title: String) {
    _title = State(initialValue: title)
}

来源: