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 提供元素删除。
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 提供元素删除。