Same here.
After removing the Option
"Use Base Internationalization"
it worked
Post
Replies
Boosts
Views
Activity
I found a solution using the tag property of the NavigationLink and @SceneStorage property wrapper.
Create a @SceneStorage (persistent state per scene)
@State private var sceneItemID: String?
or
@SceneStorage private var sceneItemID: String?
Add a tag with the unique id of the item to every NavigationLink
NavigationLink(destination: DetailView(item: $item),
tag: item.id,
selection: $sceneItemID,
label: {
RowView(item: $item)
})
Every time the Navigation Link is used the sceneItemID is updated with the tag (item.id in this case).
In the DetailView update the sceneItemID in the .onAppear() modifier.
This is necessary due to the behaviour during state change of isFav.
Now it is working only on iPad the Sidebar does not correctly display the selection. On macOS and iPhone this works.
//
// ContentView.swift
// Shared
//
// Created by Christian on 06.06.21.
//
import SwiftUI
//MARK: - Data Model
struct Item: Identifiable, Equatable, Hashable {
var id = UUID().uuidString
var isFav = false
var text: String
}
struct ItemScoped: Identifiable, Equatable, Hashable {
var id: String {
return item.id
}
var item: Item
var index: Int
}
//MARK: Store
class ItemStore: ObservableObject {
@Published var items = [Item(id: "uuid01", text: "Item 1"),
Item(id: "uuid02", text: "Item 2"),
Item(id: "uuid03", isFav: true, text: "Item 3"),
Item(id: "uuid04", text: "Item 4")]
/// scope item to sections and keep knowledge of origin index
func scopedItems(isFav: Bool) -> [ItemScoped] {
let sItems: [ItemScoped] = items.compactMap {
guard let idx = items.firstIndex(of: $0) else { return nil }
//find(items, $0)
return ItemScoped(item: $0, index: idx)
}
return sItems.filter { $0.item.isFav == isFav }
}
}
//MARK: - Views
struct ContentView: View {
// usally this is @EnvironmetObject, due to simplicity I put it here
@StateObject var store: ItemStore = ItemStore()
@SceneStorage("SceneItemSelectionID") private var sceneItemID: String?
var body: some View {
NavigationView {
List {
Section(header: Text("Favorites")) {
ForEach(store.scopedItems(isFav: true)) { scopedItems in
NavigationLink(
destination: DetailView(item: $store.items[scopedItems.index]),
//MARK: !! IMPORTANT: use unique indetifier as tag
tag: store.items[scopedItems.index].id,
selection: $sceneItemID,
label: {
RowView(item: $store.items[scopedItems.index])
})
}
}
Section(header: Text("Others")) {
ForEach(store.scopedItems(isFav: false)) { scopedItems in
NavigationLink(
destination: DetailView(item: $store.items[scopedItems.index]),
//MARK: !! IMPORTANT: use unique indetifier as tag
tag: store.items[scopedItems.index].id,
selection: $sceneItemID,
label: {
RowView(item: $store.items[scopedItems.index])
})
}
}
}
.listStyle(SidebarListStyle())
.navigationTitle("Items")
}
}
}
// MARK: Row View
/// RowView for item, tapping the text toggle the `isFav` state
struct RowView: View {
@Binding var item: Item
var body: some View {
Label(
title: { Text(item.text) },
icon: { item.isFav ? Image(systemName: "star.fill") : Image(systemName: "star")}
)
}
}
// MARK: Detail View
/// DetailView to change item `text` and toggle `isFav` state
struct DetailView: View {
@Binding var item: Item
@SceneStorage("SceneItemSelectionID") private var sceneItemID: String?
var body: some View {
VStack {
Spacer()
.frame(height: 20.0)
TextField("Title", text: $item.text)
.background(Color.gray.opacity(0.2))
.padding(10)
Toggle("is Fav:", isOn: $item.isFav.animation())
.padding()
Spacer()
}
.padding()
.onAppear() {
//MARK: !! IMPORTANT set scene selction id again
sceneItemID = item.id
}
}
}
// MARK: - Preview
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}