I've got a list in sidebar of NavigationSplitView. The view in detail should change by selecting an item. For restoration of view I'm using SceneStorage like this:
import SwiftUI
enum ListType: String {
case all = "all"
case frequently = "frequently"
}
struct MyListItem: Identifiable, Hashable {
let type: ListType
let label: String
let id = UUID()
}
struct SelectionMode: View {
@State private var listItems = [
MyListItem(type: .all, label: "alle Unterrichte"),
MyListItem(type: .frequently, label: "am häufigsten")
]
@SceneStorage("ListType") private var selectedType: ListType?
var body: some View {
NavigationSplitView {
List(listItems, id: \.self.type, selection: $selectedType) { type in
NavigationLink("\(type.label)", value: type)
}
} detail: {
NavigationStack {
SelectedList(viewType: selectedType?.rawValue ?? "all")
}
}
}
This works well, with one exception: The selected item is not highlighted in the list. First, “all” should be highlighted or the selected item (e.g. “frequently”) after the restoration. How can I achieve this?
Try this approach using a @State private var selectedItem: MyListItem?
to
do the List selection, as it matches the List display MyListItem
type set with .tag(item)
.
struct ContentView: View {
var body: some View {
SelectionMode()
}
}
enum ListType: String {
case all = "all"
case frequently = "frequently"
}
struct MyListItem: Identifiable, Hashable {
let type: ListType
let label: String
let id = UUID()
}
struct SelectionMode: View {
@State private var listItems = [
MyListItem(type: .all, label: "alle Unterrichte"),
MyListItem(type: .frequently, label: "am häufigsten")
]
// only for scenes (screens), will be lost when App is closed
// @SceneStorage("ListType") private var selectedType: ListType?
// for the whole App, for my testing, keeps the storage after App is closed
@AppStorage("ListType") private var selectedType: ListType?
@State private var selectedItem: MyListItem? // <--- here
var body: some View {
NavigationSplitView {
List(listItems, selection: $selectedItem) { item in
Text(item.label).tag(item) // <--- here
}
} detail: {
NavigationStack {
if let selectedItem = selectedItem {
SelectedList(viewType: selectedItem.type.rawValue)
} else {
Text("Select an item").font(.title)
}
}
}
.onAppear {
if selectedType == nil {
selectedType = .all
}
if let index = listItems.firstIndex(where: {$0.type == selectedType!}) {
selectedItem = listItems[index] // <--- here
}
}
.onChange(of: selectedItem) {
selectedType = selectedItem?.type // <--- here
}
}
}
struct SelectedList: View {
let viewType: String
var body: some View {
Text("Selected type: \(viewType)").font(.title)
}
}