SwiftUI中使用sizeClass时App进后台丢失SideBarView状态问题
问题核心在于:通过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
相关产品推荐
相关产品推荐

