SwiftUI中如何在不同视图结构体间访问变量?
解决SwiftUI跨视图传递选中状态的问题
问题核心
你需要将SecondView中按钮的选中状态(如tShirt)传递到Output视图,以此控制文本显示。本质是跨视图的数据传递,原代码中Output视图无法直接访问SecondView的@State变量,因为它们属于不同的作用域。
分步解决方案
1. 优化按钮组件(可选但推荐)
将点击逻辑整合到SelectButton内部,让组件更独立,避免在父视图重复编写onTapGesture:
import SwiftUI struct SelectButton: View { @Binding var isSelected: Bool let color: Color // 用let替代@State,因为不需要在组件内修改 let text: String // 同理用let var body: some View { ZStack { Capsule() .frame(height: 50) .foregroundColor(isSelected ? color : .gray) Text(text) .foregroundColor(.white) } .onTapGesture { isSelected.toggle() // 组件内部处理选中状态切换 } } } struct SelectButton_Previews: PreviewProvider { static var previews: some View { SelectButton(isSelected: .constant(false), color: .green, text: "Option") } }
2. 修正SecondView的语法错误并传递状态
原代码存在onTapGesture闭包未闭合、NavigationLink位置错误的问题,同时需要通过NavigationLink将选中状态传递给Output视图:
struct SecondView: View { @State private var tShirt = false @State private var jeans = false @State private var polo = false @State private var underpants = false var body: some View { ZStack { LinearGradient(gradient: Gradient(colors: [.blue, .white]), startPoint: .topLeading, endPoint: .bottomTrailing) .edgesIgnoringSafeArea(.all) VStack(spacing: 10) { Text("What are you washing today?") // T-Shirt按钮 SelectButton( isSelected: $tShirt, color: .green, text: "T-Shirt" ) // 其他按钮同理(Jeans、Polo等) SelectButton( isSelected: $jeans, color: .blue, text: "Jeans" ) SelectButton( isSelected: $polo, color: .orange, text: "Polo" ) SelectButton( isSelected: $underpants, color: .purple, text: "Underpants" ) // 传递tShirt状态到Output视图 NavigationLink( destination: Output(isTShirtSelected: $tShirt), label: { Text("Next") .foregroundColor(.black) }) } .padding() } } } struct SecondView_Previews: PreviewProvider { static var previews: some View { SecondView() } }
3. 修改Output视图接收状态
在Output视图中添加@Binding属性接收SecondView传递的选中状态,然后根据状态控制文本显示:
struct Output: View { @Binding var isTShirtSelected: Bool // 接收从SecondView传递的状态 var body: some View { ZStack { LinearGradient(gradient: Gradient(colors: [.blue, .white]), startPoint: .topLeading, endPoint: .bottomTrailing) .edgesIgnoringSafeArea(.all) VStack { Spacer().frame(height: 40.0) Text("Best Washing Option For You!") .font(.system(size: 25, weight: .medium)) .foregroundColor(.white) .padding(.bottom, 50.0) VStack{ HStack { Text("Degrees") .font(.system(size: 25, weight: .medium)) .foregroundColor(.white) .padding(.trailing, 200.0) } // 根据传递的状态判断是否显示文本 if isTShirtSelected { Text("James") .font(.title) Spacer().frame(height: 150.0) HStack { Text("Laundry detergent") .font(.system(size: 25, weight: .medium)) .foregroundColor(.white) .padding(.trailing, 80.0) } } Spacer() } } } } } struct Output_Previews: PreviewProvider { static var previews: some View { Output(isTShirtSelected: .constant(true)) } }
进阶优化(多选项场景)
如果后续需要支持多个选项的状态传递,建议用枚举+集合管理选中状态,避免定义大量独立的@State变量:
- 定义衣物枚举:
enum LaundryItem: String, CaseIterable { case tShirt = "T-Shirt" case jeans = "Jeans" case polo = "Polo" case underpants = "Underpants" }
- 修改
SecondView用集合管理选中项:
struct SecondView: View { @State private var selectedItems = Set<LaundryItem>() var body: some View { ZStack { LinearGradient(gradient: Gradient(colors: [.blue, .white]), startPoint: .topLeading, endPoint: .bottomTrailing) .edgesIgnoringSafeArea(.all) VStack(spacing: 10) { Text("What are you washing today?") // 遍历所有衣物选项生成按钮 ForEach(LaundryItem.allCases, id: \.self) { item in // 自定义Binding关联集合的选中状态 let binding = Binding( get: { selectedItems.contains(item) }, set: { isSelected in if isSelected { selectedItems.insert(item) } else { selectedItems.remove(item) } } ) SelectButton( isSelected: binding, color: .green, text: item.rawValue ) } NavigationLink( destination: Output(selectedItems: $selectedItems), label: { Text("Next") .foregroundColor(.black) }) } .padding() } } }
- 修改
Output视图接收集合状态:
struct Output: View { @Binding var selectedItems: Set<LaundryItem> var body: some View { ZStack { LinearGradient(gradient: Gradient(colors: [.blue, .white]), startPoint: .topLeading, endPoint: .bottomTrailing) .edgesIgnoringSafeArea(.all) VStack { Spacer().frame(height: 40.0) Text("Best Washing Option For You!") .font(.system(size: 25, weight: .medium)) .foregroundColor(.white) .padding(.bottom, 50.0) VStack{ HStack { Text("Degrees") .font(.system(size: 25, weight: .medium)) .foregroundColor(.white) .padding(.trailing, 200.0) } if selectedItems.contains(.tShirt) { Text("James") .font(.title) Spacer().frame(height: 150.0) HStack { Text("Laundry detergent") .font(.system(size: 25, weight: .medium)) .foregroundColor(.white) .padding(.trailing, 80.0) } } if selectedItems.contains(.jeans) { Text("Jeans对应的文本") .font(.title) } Spacer() } } } } }
内容的提问来源于stack exchange,提问作者Thorminator
相关产品推荐
相关产品推荐

