You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:58:24