英文:
How can I pass information between subviews in Swift
问题
我正在使用NavigationStack
来构建我的应用。在NavigationStack
中,我有多个“子”视图需要在彼此之间传递信息。例如,我的应用中有三个视图。View1负责所有视图之间的导航(由于SwiftUI的更新,这是我唯一知道如何做的方法)。在View2中,我需要将信息传递给View3(我可以使用@Binding
,但由于视图更改是在View1中处理的,所以我不能这样做。是否有更好的结构可以使用?
以下是我的代码
enum Route {
case view2
case view3
}
struct View1: View {
@State private var navigationPath: [Route] = []
var body: some View {
NavigationStack(path: $navigationPath) {
Button("前往视图2") {
navigationPath.append(.view2)
}
.background(Color.red)
.navigationDestination(for: Route.self) { route in
switch route {
case .view2:
View2(navigationPath: $navigationPath)
case .view3:
View3(navigationPath: $navigationPath)
}
}
}
}
}
struct View2: View {
@Binding var navigationPath: [Route]
var body: some View {
Button("前往视图3") {
navigationPath.append(.view3)
}
.background(Color.orange)
}
}
struct View3: View {
@Environment(\.dismiss) private var dismiss
@Binding var navigationPath: [Route]
var body: some View {
Button("弹出视图") {
navigationPath.removeLast()
// 或者 - 调用 `dismiss()`
// dismiss()
}
.background(Color.green)
}
}
英文:
I am using a NavigationStack
for my app. In the NavigationStack
, I have multiple "sub" views that need to pass information between one another. For example, I have three views in my app. View1 handles all of the navigation between the views (this is the only way I know how to do this due to the SwiftUI update). In view2, I need to pass information to view3 ( I would use a @Binding
, however, since the view change in handled in View1, I cannot do this. Is there a better structure I can use?
Here is my code
enum Route {
case view2
case view3
}
struct View1: View {
@State private var navigationPath: [Route] = []
var body: some View {
NavigationStack(path: $navigationPath) {
Button("Go to view 2") {
navigationPath.append(.view2)
}
.background(Color.red)
.navigationDestination(for: Route.self) { route in
switch route {
case .view2:
View2(navigationPath: $navigationPath)
case .view3:
View3(navigationPath: $navigationPath)
}
}
}
}
}
struct View2: View {
@Binding var navigationPath: [Route]
var body: some View {
Button("Go to view 3") {
navigationPath.append(.view3)
}
.background(Color.orange)
}
}
struct View3: View {
@Environment(\.dismiss) private var dismiss
@Binding var navigationPath: [Route]
var body: some View {
Button("Pop view") {
navigationPath.removeLast()
// or - call `dismiss()`
// dismiss()
}
.background(Color.green)
}
}
答案1
得分: 0
我认为这是使用 Navigation
和 @Binding
的最佳结构。
import SwiftUI
struct View1: View {
@State private var stackOverflow: String = "StackOverflow"
//MARK: - Body
var body: some View {
NavigationStack {
VStack {
Text("Hello World!")
NavigationLink(destination: {
View2(stackOverflow: $stackOverflow)
}, label: {
Text(stackOverflow + "View 1")
})
}
}
}//END body
}//END struct
struct View2: View {
@Binding var stackOverflow: String
@State private var showNewView: Bool = false
//MARK: - Body
var body: some View {
NavigationStack {
VStack {
Text("Hello World!")
Button(action: {
showNewView.toggle()
}, label: {
Text(stackOverflow + "View 2")
})
}
.sheet(isPresented: $showNewView, content: {
View3(stackOverflow: $stackOverflow)
})
}
}//END body
}//END struct
struct View3: View {
@Binding var stackOverflow: String
//MARK: - Body
var body: some View {
NavigationStack {
VStack {
Text("Hello World!")
Text(stackOverflow + "View 3")
}
}
}//END body
}//END struct
对于 @Binding
,你可以在此处查看更多。
对于 NavigationLink
,你可以在此处查看更多。
不要忘记在你看了之后确认我的答案是否对你有帮助
英文:
I think this is the best struct to use Navigation
and @Binding
import SwiftUI
struct View1: View {
@State private var stackOverflow: String = "StackOverflow"
//MARK: - Body
var body: some View {
NavigationStack {
VStack {
Text("Hello World!")
NavigationLink(destination: {
View2(stackOverflow: $stackOverflow)
}, label: {
Text(stackOverflow + "View 1")
})
}
}
}//END body
}//END struct
struct View2: View {
@Binding var stackOverflow: String
@State private var showNewView: Bool = false
//MARK: - Body
var body: some View {
NavigationStack {
VStack {
Text("Hello World!")
Button(action: {
showNewView.toggle()
}, label: {
Text(stackOverflow + "View 2")
})
}
.sheet(isPresented: $showNewView, content: {
View3(stackOverflow: $stackOverflow)
})
}
}//END body
}//END struct
struct View3: View {
@Binding var stackOverflow: String
//MARK: - Body
var body: some View {
NavigationStack {
VStack {
Text("Hello World!")
Text(stackOverflow + "View 3")
}
}
}//END body
}//END struct
For @Binding
you can view more here
For NavigationLink
you can view more here
Don't forget to validate my answer if it's right for you
答案2
得分: 0
我自己弄清楚了。我添加了一个AccountChangeSelector类
和一个@ObservedObject var selection = AccountChangeSelector()
。
以下是完整的代码:
class AccountChangeSelector: ObservableObject {
@Published var selection = ""
}
struct View1: View {
@State private var path = NavigationPath()
@ObservedObject var selection = AccountChangeSelector()
var body: some View {
NavigationStack(path: $path) {
Button("转到视图2") {
path.append("View2")
}
.background(Color.red)
.navigationDestination(for: String.self) { route in
switch route {
case "View2":
View2(path: $path)
case "View3":
View3(path: $path, selection: $selection)
}
}
}
}
}
struct View2: View {
@Binding var path: NavigationPath
@ObservedObject var selection: AccountChangeSelector
var body: some View {
Button("转到视图3") {
selection.selection = "View3 选择"
path.append("View3")
}
.background(Color.orange)
//...
//...
}
}
struct View3: View {
@Environment(\.dismiss) private var dismiss
@Binding var path: NavigationPath
var selection: String
var body: some View {
Button("弹出视图") {
path.removeLast()
// 或者 - 调用 `dismiss()`
// dismiss()
}
.background(Color.green)
}
}
我希望这能帮助某人,因为我为此头疼了好几天。作为一个一直使用NavigationView
和NavigationLink
的人,切换到这个应该很容易,但结果却很痛苦。
英文:
I figured it out myself. I added a AccountChangeSelector class
and a @ObservedObject var selection = AccountChangeSelector()
.
Here is the full code:
class AccountChangeSelector: ObservableObject {
@Published var selection = ""
}
struct View1: View {
@State private var path = NavigationPath()
@ObservedObject var selection = AccountChangeSelector()
var body: some View {
NavigationStack(path: $path) {
Button("Go to view 2") {
path.append("View2")
}
.background(Color.red)
.navigationDestination(for: String.self) { route in
switch route {
case "View2":
View2(path: $path)
case "View3":
View3(path: $path, selection: $selection)
}
}
}
}
}
struct View2: View {
@Binding var path: NavigationPath
@ObservedObject var selection: AccountChangeSelector
var body: some View {
Button("Go to view 3") {
selection.selection = "View3 selection"
path.append("View3")
}
.background(Color.orange)
//...
//...
}
}
struct View3: View {
@Environment(\.dismiss) private var dismiss
@Binding var path: NavigationPath
var selection: String
var body: some View {
Button("Pop view") {
navigationPath.removeLast()
// or - call `dismiss()`
// dismiss()
}
.background(Color.green)
}
}
I hope this helps someone as I had a headache over this for days. As someone who always used NavigationView
& NavigationLink
, switching to this was supposed to be easy, but turned out to be a pain.
答案3
得分: 0
View Model Solution (A)
这将允许数据来回移动,您可以使用viewModel.someView
作为State
变量
ViewModel
final class ViewModel: ObservableObject {
@Published var someVa: String = ""
enum Route {
case view2
case view3
}
}
View1
struct View1: View {
@State private var navigationPath: [ViewModel.Route] = []
@StateObject var viewModel = ViewModel()
var body: some View {
NavigationStack(path: $navigationPath) {
Button("转到视图2") {
navigationPath.append(.view2)
}
.background(Color.red)
Text(viewModel.someVar)
.navigationDestination(for: ViewModel.Route.self) { route in
switch route {
case .view2:
View2(navigationPath: $navigationPath, viewModel: viewModel)
case .view3:
View3(navigationPath: $navigationPath, viewModel: viewModel)
}
}
}
}
}
View2
struct View2: View {
@Binding var navigationPath: [ViewModel.Route]
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Button("转到视图3") {
navigationPath.append(.view3)
}
.background(Color.orange)
Text(viewModel.someVar)
}
}
}
View3
struct View3: View {
@Environment(\.dismiss) private var dismiss
@Binding var navigationPath: [ViewModel.Route]
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Button("弹出视图") {
navigationPath.removeLast()
// 或者 - 调用 `dismiss()`
// dismiss()
}
.background(Color.green)
Text(viewModel.someVar)
}
}
}
Enum Solution (B)
这只允许从父视图向前移动数据
Enum
enum Route {
case view2(someVar: String)
case view3(someVar: String)
}
英文:
You can use a ViewModel solution or pass variable through the enums.
View Model Solution (A)
This will allow movement of the data back and forth, you can use the viewModel.someView
as a State
var
ViewModel
final class ViewModel: ObservableObject {
@Published var someVa: String = ""
enum Route {
case view2
case view3
}
}
View1
struct View1: View {
@State private var navigationPath: [ViewModel.Route] = []
@StateObject var viewModel = ViewModel()
var body: some View {
NavigationStack(path: $navigationPath) {
Button("Go to view 2") {
navigationPath.append(.view2)
}
.background(Color.red)
Text(viewModel.someVar)
.navigationDestination(for: ViewModel.Route.self) { route in
switch route {
case .view2:
View2(navigationPath: $navigationPath, viewModel: viewModel)
case .view3:
View3(navigationPath: $navigationPath, viewModel: viewModel)
}
}
}
}
}
View2
struct View2: View {
@Binding var navigationPath: [ViewModel.Route]
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Button("Go to view 3") {
navigationPath.append(.view3)
}
.background(Color.orange)
Text(viewModel.someVar)
}
}
}
View3
struct View3: View {
@Environment(\.dismiss) private var dismiss
@Binding var navigationPath: [ViewModel.Route]
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Button("Pop view") {
navigationPath.removeLast()
// or - call `dismiss()`
// dismiss()
}
.background(Color.green)
Text(viewModel.someVar)
}
}
}
Enum Solution (B)
This will only allow a forward move of data from the parent view
Enum
enum Route {
case view2(someVar: String)
case view3(someVar: String)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论