在列表顶部插入项目时如何保持 LazyVStack / VStack 中的滚动位置

nRe*_*wik 7 ios swift swiftui

我创建了一个简单的垂直列表,其中包含要显示的项目。

问题是当我通过 . 在列表顶部插入项目时insertAtTop()。滚动视图不会停留在同一个位置。

观看视频: https: //streamable.com/i7ywab


如何使滚动视图保持在同一位置?

这是示例代码。

struct TestView: View {
    
    @State private var items: [Item] = []
    
    var body: some View {
        NavigationView {
            ScrollView {
                LazyVStack {
                    ForEach(items, id: \._id) { item in
                        Text(item.text)
                            .background(Color.green)
                            .padding(.bottom, 10)
                    }
                }
            }
            .navigationBarItems(trailing: HStack {
                Button("[Insert at top]", action: {
                    insertAtTop()
                })
                Spacer(minLength: 20)
                Button("[Load]", action: {
                    load()
                })
            })
            .navigationTitle("Item List")
        }
    }
    
    private func load() {
        items = (1...50).map { _ in Item() }
    }
    
    private func insertAtTop() {
        let newItems = (1...20).map { _ in Item() }
        items.insert(contentsOf: newItems, at: 0)
    }
    
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}

struct Item {
    var _id = UUID()
    var text = UUID().uuidString.prefix(5)
}
Run Code Online (Sandbox Code Playgroud)

Jac*_*mon 0

仅当您在列表顶部添加视图时,问题似乎才会出现。如果您修改替换现有视图,则不会有问题。

...所以一种解决方法是在负方向上具有大量视图(例如 10000)的占位符数组上循环 ForEach。然后在 ForEach 中,检查索引以查看它是否存在于真实/非占位符数组中。

如果是 -> 真实视图 如果不是 -> 廉价视图(例如具有正确背景颜色且高度为 1 的 Rectangle())。

LazyVStack {
    ForEach(placeholderIndices, id: \.self) { index in
        if indices.contains(index) {
            REAL VIEW
        } else {
            Rectangle()
                .fill(Color.bg)
                .frame(height: 0)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当您扩展视图时,placeholderIndices 保持不变;只有“真实”指数发生变化