SwiftUI - .scrollPosition 修饰符不更新绑定属性

Göt*_*ötz 5 swiftui

我尝试使用按钮将 ScrollView 设置为最顶部的元素。因此,新的.scrollPosition()修饰符应该会派上用场。我无法让它工作。在以下示例中,当单击堆栈底部的项目或按钮时,滚动将起作用。但滚动时该值不会更新。您可以通过滚动到底部、单击“滚动到顶部”按钮并向下滚动来重现该行为。第二次,什么也没有发生,因为值仍然是 1。我做错了什么,还是我对修饰符的期望错误?文档是这样说的: https://developer.apple.com/documentation/swiftui/view/scrollposition(id:anchor:)

\n
//\n//  ContentView.swift\n//  Test\n//\n//  Created by Sebastian G\xc3\xb6tte on 23.09.23.\n//\n\nimport SwiftUI\n\nstruct ContentView: View {\n    \n    @State private var scrollViewPosition: Int?\n    \n    var body: some View {\n        ScrollView(.vertical) {\n            VStack(spacing: 32) {\n                ForEach(1..<21) { item in\n                    Text("I am item no. \\(item)")\n                        .id(item)\n                    \n                        .frame(maxWidth: .infinity)\n                        .padding()\n                        .background(.purple)\n                        .cornerRadius(4)\n                    \n                        .onTapGesture {\n                            withAnimation {\n                                scrollViewPosition = item\n                            }\n                        }\n                }\n                \n                Button("Scroll to top", action: {\n                    withAnimation {\n                        scrollViewPosition = 1\n                    }\n                })\n            }\n            .scrollTargetLayout()\n            .scrollTargetBehavior(.viewAligned)\n            .padding()\n        }\n        .scrollPosition(id: $scrollViewPosition, anchor: .top)\n        \n        .onChange(of: scrollViewPosition) { oldValue, newValue in\n        print(newValue ?? "No value set")\n        }\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

rob*_*off 4

如果您更改VStackLazyVStack,您的代码就可以工作。

LazyVStack但是,您可能会因某种原因而无法使用。例如,在我的应用程序中,我LayoutScrollView.

如果您无法使用LazyVStack, ,那么(在我对 iOS 17.0.1 的测试中),使用.id修饰符会阻止 SwiftUI 更新绑定scrollPosition.id您需要依赖ForEach将 an 分配id给其每个子视图的行为,而不是使用。ForEach这也意味着您需要使用带有参数的版本id:,或者为其提供符合标准的值的集合Identifiable

因此,为了使您的示例正常工作,请将ForEach循环更改为:

ForEach(1..<21, id: \.self) { item in
    Text("I am item no. \(item)")
        // .id modifier removed
        .frame(maxWidth: .infinity)
        .padding()
        .background(.purple)
        .cornerRadius(4)
        .onTapGesture {
            withAnimation {
                scrollViewPosition = item
            }
        }
}
Run Code Online (Sandbox Code Playgroud)