SwiftUI多视图问卷跨视图状态持久化问题求助
SwiftUI多视图问卷状态持久化解决方案
问题根源
当前每个按钮的@State是局部状态,视图销毁(比如从运动页返回姓名页)后状态会重置,且无法在多视图间共享选择数据。需要用ObservableObject创建共享数据模型,实现跨视图状态同步。
解决方案步骤
1. 创建共享数据模型
定义一个遵循ObservableObject的类,用@Published修饰需要监听的属性,确保属性变化时通知视图更新:
import SwiftUI import Combine class UserSelection: ObservableObject { @Published var selectedName: String? = nil @Published var selectedSports: [String] = [] }
2. 在根视图初始化并注入模型
假设你的根视图是ContentView,用@StateObject初始化模型,然后通过environmentObject注入到整个视图层级,让所有子视图都能访问:
struct ContentView: View { @StateObject private var userSelection = UserSelection() var body: some View { Names() .environmentObject(userSelection) } }
3. 修改姓名选择视图(Names)
移除按钮的局部@State,改用共享模型的selectedName判断选中状态,点击时更新模型:
struct Names: View { private let names = ["xyz", "zfx", "abc", "def", "ghij", "klm"] @EnvironmentObject private var userSelection: UserSelection // 接收共享模型 var body: some View { NavigationView{ VStack{ Text("Choose your name") .font(.largeTitle) .foregroundColor(Color("LightBlue")) .padding(.bottom, 40) .padding(.top, 40) VStack(spacing: 20){ ForEach(names, id: \.self){ name in CustomButton(name: name, isSelected: userSelection.selectedName == name) { userSelection.selectedName = name // 更新选中姓名 } } } } } } } // 重构CustomButton,依赖外部状态和回调 struct CustomButton: View { let name: String let isSelected: Bool let onTap: () -> Void var body: some View { Button(action: onTap) { NavigationLink(destination: ChooseSports()){ Text(name) .font(.subheadline) .frame(width: 250, height: 60) .background(isSelected ? Color("DarkBlue") : .white) .foregroundColor(isSelected ? .white : Color("DarkBlue")) .cornerRadius(50) .overlay( RoundedRectangle(cornerRadius: 50) .stroke(Color("DarkBlue"), lineWidth: 2) ) } } } }
4. 修改运动选择视图(ChooseSports)
同样接收共享模型,用selectedSports数组管理选中状态,点击时添加/移除运动:
struct ChooseSports: View { private let sports = ["tennis", "football", "golf", "basketball", "squash", "badminton", "swimming", "skiing"] @EnvironmentObject private var userSelection: UserSelection // 接收共享模型 var body: some View { ScrollView{ VStack{ Text("Choose your favourite sports") .font(.largeTitle) .foregroundColor(Color("LightBlue")) .padding(.bottom, 40) .padding(.top, 40) VStack(spacing: 20){ ForEach(sports, id: \.self){ sport in CustomButton2(name: sport, isSelected: userSelection.selectedSports.contains(sport)) { if userSelection.selectedSports.contains(sport) { userSelection.selectedSports.removeAll { $0 == sport } } else { userSelection.selectedSports.append(sport) } } } } } } } } // 重构CustomButton2,依赖外部状态和回调 struct CustomButton2: View { let name: String let isSelected: Bool let onTap: () -> Void var body: some View { Button(action: onTap) { Text(name) .font(.subheadline) .frame(width: 250, height: 60) .background(isSelected ? Color("DarkBlue") : .white) .foregroundColor(isSelected ? .white : Color("DarkBlue")) .cornerRadius(50) .overlay( RoundedRectangle(cornerRadius: 50) .stroke(Color("DarkBlue"), lineWidth: 2) ) } } }
关键说明
@StateObject只能在根视图初始化,子视图用@EnvironmentObject或@ObservedObject接收,确保整个视图层级共享同一个模型实例。- 所有状态判断和修改都基于共享模型,视图只负责展示和触发修改,避免局部状态丢失问题。
- 模型的
@Published属性会自动触发视图更新,保证多视图状态同步。
内容的提问来源于stack exchange,提问作者unknownUser
相关产品推荐
相关产品推荐

