在SwiftUI中实现从一个视图向另一个视图传递并展示数据
实现Recipe列表到详情页的跳转与数据传递
没问题,我帮你搞定这个需求,分几步来实现:
第一步:修改详情视图,让它能接收选中的Recipe数据
首先你的RecipeController目前是硬编码使用整个食谱列表,我们需要改成接收单个选中的RecipeListModel对象,这样才能展示对应的数据:
struct RecipeController: View { @State var recipeEdit = true // 新增:添加属性接收选中的食谱对象 var selectedRecipe: RecipeListModel var body: some View { NavigationView{ VStack{ // 替换成展示选中食谱的名称 Text(selectedRecipe.name) .font(.title) // 如果RecipeEntryPicture需要展示对应食谱的图片,也要给它传参(示例见最后补充) RecipeEntryPicture(selectedRecipe: selectedRecipe) RecipeIngredients(isEditing: $recipeEdit) // 你还可以在这里添加更多展示选中食谱信息的控件,比如食材列表、烹饪步骤等 } .toolbar{ ToolbarItem(placement: .bottomBar){ Button(action: { recipeEdit.toggle() }){ HStack{ Image(systemName: "pencil.circle").foregroundColor(.black) Text(recipeEdit ? "Edit" : "Complete") .foregroundColor(.black) } .font(.title) } .edgesIgnoringSafeArea(.all) .frame(maxWidth: .infinity) .frame(height: 60) .background(Color(recipeEdit ? "spaceGray" : "completeGreen")) } } // 设置导航栏标题为选中食谱的名称 .navigationTitle(selectedRecipe.name) } } }
第二步:在列表视图实现跳转逻辑
这里有两种常用的实现方式,你可以根据需求选择:
方式1:直接用NavigationLink包裹按钮(最简单)
这种方式适合不需要额外前置逻辑的场景,点击按钮直接跳转:
struct RecipeListView: View { var listofRecipes: [RecipeListModel] = RecipeList.recipes init(){ UITableView.appearance().backgroundColor = .clear } var body: some View { NavigationView{ VStack{ Text("Recipes") .padding(.top, 40) .font(.title2) List(listofRecipes, id: \.id){ recipe in HStack{ Image(recipe.image) .resizable() .frame (width: 70, height:70) .cornerRadius(15) VStack{ Text(recipe.name) .font(.title3) // 用NavigationLink包裹按钮,点击即跳转并传递当前recipe NavigationLink(destination: RecipeController(selectedRecipe: recipe)) { Text("View Recipe") .font(.body) .foregroundColor(.white) .frame(width:120, height:30) .background(Color("completeGreen")) } } .padding(.leading, 40) } } } } } }
方式2:用状态变量控制跳转(适合需要前置逻辑的场景)
如果需要在跳转前做一些额外操作(比如打印日志、数据校验、网络请求),可以用状态变量结合隐藏的NavigationLink:
struct RecipeListView: View { var listofRecipes: [RecipeListModel] = RecipeList.recipes // 新增:存储选中的食谱,用来控制跳转状态 @State private var selectedRecipe: RecipeListModel? = nil init(){ UITableView.appearance().backgroundColor = .clear } var body: some View { NavigationView{ VStack{ Text("Recipes") .padding(.top, 40) .font(.title2) List(listofRecipes, id: \.id){ recipe in HStack{ Image(recipe.image) .resizable() .frame (width: 70, height:70) .cornerRadius(15) VStack{ Text(recipe.name) .font(.title3) Button(action: { // 这里可以添加跳转前的额外逻辑,比如: print("即将跳转至食谱:\(recipe.name)") // 标记选中的食谱,触发跳转 selectedRecipe = recipe }){ Text("View Recipe") .font(.body) .foregroundColor(.white) .frame(width:120, height:30) .background(Color("completeGreen")) } } .padding(.leading, 40) } } // 隐藏的NavigationLink,当selectedRecipe不为空时自动跳转 .background( NavigationLink( destination: RecipeController(selectedRecipe: selectedRecipe!), isActive: Binding( get: { selectedRecipe != nil }, set: { if !$0 { selectedRecipe = nil } } ) ) { EmptyView() } ) } } } }
补充:给子视图传递选中的Recipe数据
如果你的RecipeEntryPicture需要展示对应食谱的图片,也要给它添加接收参数的属性:
struct RecipeEntryPicture: View { var selectedRecipe: RecipeListModel var body: some View { Image(selectedRecipe.image) .resizable() .aspectRatio(contentMode: .fit) .cornerRadius(15) .padding() } }
可选:iOS 16+推荐使用NavigationStack
如果你是针对iOS 16及以上版本开发,建议用NavigationStack替代NavigationView,用法基本一致,只需要把NavigationView换成NavigationStack即可,更适合复杂的导航场景。
内容的提问来源于stack exchange,提问作者Swink
相关产品推荐
相关产品推荐

