iPad端NavigationSplitView后台返回丢失列表选中状态问题
问题描述
在iPad设备上,使用NavigationSplitView实现的列表,按下Home键回到桌面再返回应用后,之前选中的列表项状态会丢失;相同场景下使用NavigationView则能正常保留选中状态,且该问题仅出现在iPad,iPhone无此现象。
有问题的NavigationSplitView代码
import SwiftUI struct NavigationSplitViewExample: View { private var alphabets = ["A","B","C"] @State private var alphabetChosen: String? var body: some View { NavigationSplitView(columnVisibility: .constant(NavigationSplitViewVisibility.all)) { List(alphabets, id:\.self, selection: $alphabetChosen) { alphabets in Text(alphabets) } } detail: { Text(alphabetChosen ?? "0") } } }
正常保留状态的NavigationView代码
struct ContentView: View { private var alphabets = ["A","B","C"] @State private var alphabetChosen: String? let columns = Array(repeating: GridItem(.adaptive(minimum: 94, maximum: 120)), count: 3) var body: some View { NavigationView { List(alphabets, id:\.self) { alphabet in NavigationLink(destination: Text("chosen \(alphabet)")) { Text(alphabet) } } } .navigationBarTitle(Text("Alphabets")) .navigationViewStyle(StackNavigationViewStyle()) } }
问题原因
NavigationSplitView在iPad上的状态管理逻辑和NavigationView存在差异:当应用进入后台时,@State修饰的选中状态变量会被系统重置。NavigationSplitView的列选中状态依赖于自身的绑定变量,而后台恢复时系统没有自动保留这个@State变量的值;反观NavigationView,它通过NavigationLink维护的导航栈自动保留了选中对应的页面状态。
解决方案
方案1:使用@AppStorage持久化状态
@AppStorage会将状态存储到用户默认配置中,跨应用后台恢复、甚至重启都能保留选中状态:
import SwiftUI struct NavigationSplitViewExample: View { private var alphabets = ["A","B","C"] // 用AppStorage替代State,指定存储键名 @AppStorage("selectedAlphabet") private var alphabetChosen: String? var body: some View { NavigationSplitView(columnVisibility: .constant(NavigationSplitViewVisibility.all)) { List(alphabets, id:\.self, selection: $alphabetChosen) { alphabet in Text(alphabet) } } detail: { Text(alphabetChosen ?? "0") } } }
方案2:使用@SceneStorage存储场景状态
@SceneStorage是专门为场景状态设计的存储方案,仅保留当前场景的状态,更轻量化,适合仅需后台恢复时保留状态的场景:
import SwiftUI struct NavigationSplitViewExample: View { private var alphabets = ["A","B","C"] // 用SceneStorage替代State,指定存储键名 @SceneStorage("selectedAlphabet") private var alphabetChosen: String? var body: some View { NavigationSplitView(columnVisibility: .constant(NavigationSplitViewVisibility.all)) { List(alphabets, id:\.self, selection: $alphabetChosen) { alphabet in Text(alphabet) } } detail: { Text(alphabetChosen ?? "0") } } }
两种方案对比
@AppStorage:数据持久化到系统偏好设置,跨场景、跨应用重启有效;@SceneStorage:数据绑定到当前场景,仅在当前场景后台恢复时有效,不会影响其他场景,更适合多窗口场景。
内容的提问来源于stack exchange,提问作者nirav dinmali
相关产品推荐
相关产品推荐

