嵌套在 ScrollView 中的 SwiftUI ForEach 打破了 onPreferenceChange
SwiftUI ForEach nested in ScrollView breaks onPreferenceChange
我正在尝试获取 ScrollView
的当前 滚动值 ,以便在其他视图的其他地方使用。
似乎唯一的方法是使用 GeometryReader
并将其值存储在 PreferenceKey
中,然后由 onPreferenceChange
读取,这样我们就不会改变 onPreferenceChange
的状态渲染期间的视图(禁止)。
一切似乎都正常,直到我在滚动视图中嵌入 ForEach 而不是一些静态视图。然后 onPreferenceChange
停止接收事件。
这是一个 NON 工作示例:
struct ScrollViewPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
struct ContentView: View {
var body: some View {
ScrollView {
GeometryReader { proxy in
Color.clear.preference(key: ScrollViewPreferenceKey.self,
value: proxy.frame(in: .named("scrollview")).minY)
}
VStack(spacing: 20) {
ForEach(0..<27) { item in // this is causing the issue
Text("Item \(item)")
}
} //end vstack
} //end scrollview
.coordinateSpace(name: "scrollview")
.onPreferenceChange(ScrollViewPreferenceKey.self, perform: { value in
let _ = print(value)
})
}//endbody
} //endview
结果没有打印任何东西
用硬编码视图替换 ForEach { }
效果很好:
Group {
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
}
Group {
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
}
Group {
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
}
打印正确值的结果
0.0
-11.666666666666664
-49.333333333333336
-104.33333333333334
-174.33333333333331
-252.66666666666666
-315.0
...
我认为滚动视图和动态内容一定存在问题,但如何解决?
即使 ForEach 在层次结构或其他文件中嵌入了多层视图,也会出现此问题。
这只是另一个 SwiftUI 错误还是我没有掌握某些东西(我是框架的新手)?
简单
struct ContentView: View {
var body: some View {
ScrollView {
GeometryReader { proxy in
Color.clear.preference(key: ScrollViewPreferenceKey.self,
value: proxy.frame(in: .named("scrollview")).minY)
}
ForEach(0..<27, id: \.self) { item in // this is causing the issue
Text("Item \(item)")
.padding()
}
} //end scrollview
.coordinateSpace(name: "scrollview")
.onPreferenceChange(ScrollViewPreferenceKey.self, perform: { value in
let _ = print(value)
})
}//endbody
} //endview
成功了。 VStack 导致了问题。
我正在尝试获取 ScrollView
的当前 滚动值 ,以便在其他视图的其他地方使用。
似乎唯一的方法是使用 GeometryReader
并将其值存储在 PreferenceKey
中,然后由 onPreferenceChange
读取,这样我们就不会改变 onPreferenceChange
的状态渲染期间的视图(禁止)。
一切似乎都正常,直到我在滚动视图中嵌入 ForEach 而不是一些静态视图。然后 onPreferenceChange
停止接收事件。
这是一个 NON 工作示例:
struct ScrollViewPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
struct ContentView: View {
var body: some View {
ScrollView {
GeometryReader { proxy in
Color.clear.preference(key: ScrollViewPreferenceKey.self,
value: proxy.frame(in: .named("scrollview")).minY)
}
VStack(spacing: 20) {
ForEach(0..<27) { item in // this is causing the issue
Text("Item \(item)")
}
} //end vstack
} //end scrollview
.coordinateSpace(name: "scrollview")
.onPreferenceChange(ScrollViewPreferenceKey.self, perform: { value in
let _ = print(value)
})
}//endbody
} //endview
结果没有打印任何东西
用硬编码视图替换 ForEach { }
效果很好:
Group {
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
}
Group {
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
}
Group {
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
Text("Item x")
}
打印正确值的结果
0.0 -11.666666666666664 -49.333333333333336 -104.33333333333334 -174.33333333333331 -252.66666666666666 -315.0 ...
我认为滚动视图和动态内容一定存在问题,但如何解决?
即使 ForEach 在层次结构或其他文件中嵌入了多层视图,也会出现此问题。
这只是另一个 SwiftUI 错误还是我没有掌握某些东西(我是框架的新手)?
简单
struct ContentView: View {
var body: some View {
ScrollView {
GeometryReader { proxy in
Color.clear.preference(key: ScrollViewPreferenceKey.self,
value: proxy.frame(in: .named("scrollview")).minY)
}
ForEach(0..<27, id: \.self) { item in // this is causing the issue
Text("Item \(item)")
.padding()
}
} //end scrollview
.coordinateSpace(name: "scrollview")
.onPreferenceChange(ScrollViewPreferenceKey.self, perform: { value in
let _ = print(value)
})
}//endbody
} //endview
成功了。 VStack 导致了问题。