SwiftUI List 在任何视图更改时重置滚动

SwiftUI List reset scroll on any view change

I have a very simple List with some Sections, in the same view I have also one button which will become enabled when any of list items are selected, this is controlled with a State variable, when this is happening, if列表向下滚动,状态变量将更改(以启用按钮)并且所有视图将刷新,导致我的列表滚动到顶部。我怎样才能避免这种滚动重置,我应该提到如果元素被删除或添加到列表中也会发生同样的情况,但是,我试图尽可能地简化问题,这里是简化的代码片段。

import SwiftUI

enum FavoritesListActiveSheet: Identifiable {
    case moveToSheet
    
    var id: Int { hashValue }
}

struct Category: Identifiable {
    var id: UUID = UUID()
    var name: String
}

extension Category {
    static var categories: [Category] {
        [
            Category(name: "category 1"),
            Category(name: "category 2")
        ]
    }
}

struct FavoriteItem: Identifiable {
    var id: UUID = UUID()
    var name: String
    var category: String
    var selected: Bool
}

extension FavoriteItem {
    static var favoriteItems: [FavoriteItem] {
        [
            FavoriteItem(name: "Item 1", category: "category 1", selected: false),
            FavoriteItem(name: "Item 2", category: "category 1", selected: false),
            FavoriteItem(name: "Item 3", category: "category 1", selected: false),
            FavoriteItem(name: "Item 4", category: "category 2", selected: false),
            FavoriteItem(name: "Item 5", category: "category 2", selected: false),
            FavoriteItem(name: "Item 6", category: "category 2", selected: false),
            FavoriteItem(name: "Item 7", category: "category 2", selected: false),
            FavoriteItem(name: "Item 8", category: "category 2", selected: false),
            FavoriteItem(name: "Item 9", category: "category 2", selected: false),
            FavoriteItem(name: "Item 10", category: "category 2", selected: false),
            FavoriteItem(name: "Item 11", category: "category 2", selected: false),
            FavoriteItem(name: "Item 12", category: "category 2", selected: false),
            FavoriteItem(name: "Item 13", category: "category 2", selected: false),
            FavoriteItem(name: "Item 14", category: "category 2", selected: false),
            FavoriteItem(name: "Item 15", category: "category 2", selected: false),
            FavoriteItem(name: "Item 16", category: "category 2", selected: false),
            FavoriteItem(name: "Item 17", category: "category 2", selected: false),
            FavoriteItem(name: "Item 18", category: "category 2", selected: false),
        ]
    }
}

struct FavoritesRaw: View {

    @Binding var item: FavoriteItem
    @State var refreshView: Bool = false

    let onItemToggle: () -> ()

    var body: some View {
        HStack {
            if (item.selected) {
                Image(systemName: "checkmark.circle")
            } else {
                Image(systemName: "circle")
            }

            Text (item.name)
        }
        .simultaneousGesture(TapGesture().onEnded {

            self.item.selected.toggle()

            refreshView.toggle()
            onItemToggle()
        })
        .contentShape(Rectangle())
    }
}

class FavoritesViewModel: ObservableObject {
    var favorite_items: [FavoriteItem] = FavoriteItem.favoriteItems
}

struct FavoritesListView: View {
    @StateObject var viewModel: FavoritesViewModel = FavoritesViewModel()

    @State var addtoButtonDisabled: Bool = true
    @State var sheetDisplayed: FavoritesListActiveSheet?

    var body: some View {
        NavigationView {
            VStack {
                List {
                    ForEach (Category.categories) { category in
                        Section (header: Text(category.name))
                        {
                            ForEach (self.viewModel.favorite_items.filter({[=10=].category == category.name})) { item in
                                FavoritesRaw(item: binding(for: item), onItemToggle: {
                                    addtoButtonDisabled = (self.viewModel.favorite_items.filter({[=10=].selected == true}).count == 0)
                                })
                            }
                        }
                        .textCase(nil)
                        
                    }
                }
                .listStyle(PlainListStyle())
                .id(UUID()) // no animation
            }
            .navigationBarTitle("Favorites", displayMode: .inline)
            .toolbar {
                ToolbarItemGroup(placement: .navigationBarTrailing) {

                    Button(action: {
                        sheetDisplayed = .moveToSheet
                    }) {
                        Text("Add to...")
                    }.disabled(addtoButtonDisabled)
                }
            }
            .sheet(item: $sheetDisplayed) { item in
                // [Show a sheet then disable back the button]
            }
        }
        .onAppear
        {
            addtoButtonDisabled = (self.viewModel.favorite_items.filter({[=10=].selected == true}).count == 0)
        }
    }

    private func binding(for item: FavoriteItem) -> Binding<FavoriteItem> {
        guard let item_index = self.viewModel.favorite_items.firstIndex(where: { [=10=].id == item.id }) else {
             fatalError("Can't find item in array")
         }
        return $viewModel.favorite_items[item_index]
     }
}

似乎删除

.id(UUID()) // 没有动画

正在解决我的问题。但是,我添加这个是为了摆脱丑陋的动画,SwiftUI 提供元素删除。