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

SwiftUI中使用sizeClass时App进后台丢失SideBarView状态问题

解决SideBarView在sizeClass判断下丢失状态的问题

问题核心在于:通过sizeClass条件分支渲染视图时,每次App进入后台(或sizeClass发生变化),SideBarView会被销毁并重新初始化,导致其内部状态丢失。直接渲染SideBarView时无此问题,是因为视图实例始终存在,状态得以保留。

以下是可行的解决思路:

1. 将SideBarView的状态抽离至外部ViewModel

把SideBarView的所有状态(如选中项、展开状态等)转移到遵循ObservableObject的ViewModel类中,让状态生命周期独立于视图本身。

步骤示例:

  • 定义ViewModel类:
import SwiftUI

class SideBarViewModel: ObservableObject {
    @Published var selectedMenu: String = "首页"
    @Published var isMenuExpanded: Bool = true
    // 其他需要保留的状态变量
}
  • 在父视图中持有ViewModel实例,并传递给SideBarView:
struct MainContentView: View {
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    // 使用@StateObject确保ViewModel生命周期与父视图一致
    @StateObject private var sidebarViewModel = SideBarViewModel()
    
    var body: some View {
        #if os(iOS)
        if horizontalSizeClass == .compact {
            TabMainView()
        } else {
            SideBarView(viewModel: sidebarViewModel)
        }
        #else
            SideBarView(viewModel: sidebarViewModel)
        #endif
    }
}
  • 修改SideBarView接收ViewModel:
struct SideBarView: View {
    @ObservedObject var viewModel: SideBarViewModel
    
    var body: some View {
        List {
            Button(viewModel.selectedMenu == "首页" ? "✅ 首页" : "首页") {
                viewModel.selectedMenu = "首页"
            }
            Button(viewModel.selectedMenu == "设置" ? "✅ 设置" : "设置") {
                viewModel.selectedMenu = "设置"
            }
        }
        .listStyle(.sidebar)
    }
}

2. 使用环境对象传递状态

如果SideBarView在多个地方被使用,可将ViewModel通过.environmentObject注入环境,避免手动传递:

// 父视图中注入环境对象
struct MainContentView: View {
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    @StateObject private var sidebarViewModel = SideBarViewModel()
    
    var body: some View {
        #if os(iOS)
        if horizontalSizeClass == .compact {
            TabMainView()
                .environmentObject(sidebarViewModel)
        } else {
            SideBarView()
                .environmentObject(sidebarViewModel)
        }
        #else
            SideBarView()
                .environmentObject(sidebarViewModel)
        #endif
    }
}

// SideBarView中读取环境对象
struct SideBarView: View {
    @EnvironmentObject var viewModel: SideBarViewModel
    
    var body: some View {
        // 视图内容...
    }
}

3. 用@SceneStorage保存关键状态(可选)

如果sizeClass在App后台时被系统临时修改导致视图切换,可尝试用@SceneStorage保存关键状态,即使视图重建也能恢复:

struct SideBarView: View {
    @SceneStorage("sidebarSelectedItem") private var selectedItem: String = "首页"
    
    var body: some View {
        // 使用selectedItem状态...
    }
}

@SceneStorage会将状态绑定到App的场景存储,即使视图销毁重建,也能从存储中恢复状态。

内容的提问来源于stack exchange,提问作者LucasC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:17:03