简体   繁体   English

SwiftUI 列表重置滚动任何视图更改

[英]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 list is scrolled down, State variable will change (to enable the button) and all view will refresh, causing my list to scroll on top. 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 list is scrolled down, State 变量将更改(启用按钮)并且所有视图将刷新,导致我的列表滚动到顶部。 How can I avoid this scroll reset, I should mention that the same is happening if elements are removed or added to the list, however, I tried to simplify the problem as much as possible, here is the simplified code snippet.我怎样才能避免这种滚动重置,我应该提到如果元素被删除或添加到列表中也会发生同样的情况,但是,我试图尽可能地简化问题,这里是简化的代码片段。

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({$0.category == category.name})) { item in
                                FavoritesRaw(item: binding(for: item), onItemToggle: {
                                    addtoButtonDisabled = (self.viewModel.favorite_items.filter({$0.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({$0.selected == true}).count == 0)
        }
    }

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

It seems that removing好像去掉

.id(UUID()) // no animation .id(UUID()) // 没有 animation

is fixing my problem.正在解决我的问题。 However, I've added this to get rid of the ugly animation, SwiftUI is providing on element delete.但是,我添加了这个来摆脱丑陋的 animation,SwiftUI 在元素删除时提供。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM