英文:
onPreferenceChange not called on geometryReader frame change
问题
`PreferenceKey` 定义
```swift
struct ScrollPrefKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
主要代码
ScrollView {
GeometryReader { proxy in
Text("\(proxy.frame(in: .named("scroll")).minY)") // 我可以看到变化
Color.clear.preference(key: ScrollPrefKey.self, value: proxy.frame(in: .named("scroll")).minY)
} //MARK: 结束 GeometryReader
VStack {
// 主要内容
Button(action: {}, label: {Text("我的按钮")})
}
}
.coordinateSpace(name: "scroll")
.onPreferenceChange(ScrollPrefKey.self, perform: { value in
print(value)
// 做一些操作 - 但它从未触发
})
- 这段代码在预览中工作,但在模拟器中不工作(iOS 16.1)。
- 将 VStack 替换为具有定义高度的静态 Color 可以工作。
- 嵌入包括
GeometryReader
在内的整个 scrollView 内容仍然不起作用。
<details>
<summary>英文:</summary>
`PreferenceKey` definition
struct ScrollPrefKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
Main Code
ScrollView {
GeometryReader { proxy in
Text("\(proxy.frame(in: .named("scroll")).minY)") // I can see changes
Color.clear.preference(key: ScrollPrefKey.self, value: proxy.frame(in: .named("scroll")).minY)
} //MARK: END GeometryReader
VStack {
//main content
Button(action: {}, label: {Text("myButton")})
}
}
.coordinateSpace(name: "scroll")
.onPreferenceChange(ScrollPrefKey.self, perform: { value in
print(value)
//DO SOME THINGS - but it never trigger
})
1. This code works in Preview but not using simulator (iOS 16.1)
2. Replacing VStack with a static Color with defined height works
3. Embedding the entire content of scrollView including `GeometryReader` still doesn't work
</details>
# 答案1
**得分**: 2
`nextValue: () -> Self.Value`:这个函数允许对所有这些偏好进行逻辑归约,如果多个不同的视图输出多个值,都使用相同的PreferenceKey。
当视图首次加载时,偏好键将从`defaultValue`更新到初始值。由于只有一个视图产生带有一个偏好键的值,所以在这种情况下`nextValue()`返回nil。
`value: inout Self.Value`:
尽管`value`在之前的调用中持续累积并随着偏好键值的更改而更新。因此,我们应该在这里使用`value`。
在代码中使用以下方式更新`PreferenceKey`的定义:
```swift
struct ScrollPrefKey: PreferenceKey {
static var defaultValue: CGFloat? = nil
static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) {
value = value ?? nextValue()
}
}
英文:
static func reduce(value: inout Self.Value, nextValue: () -> Self.Value)
nextValue: () -> Self.Value
: This function allows for logic to reduce all those preferences to a single value, if multiple values are outputted by multiple different views, all using the same PreferenceKey.
When the view loads first time, the preference key will be updated from defaultValue
to initial value. And since we have only one view producing the value with one preference key, the nextValue()
returns nil in this case.
value: inout Self.Value
:
Though the value
, which is keep accumulating through previous calls and keeps updating with the preference key value changes. So we should use the value
here.
Update the PreferenceKey
definition in the code with this:
struct ScrollPrefKey: PreferenceKey {
static var defaultValue: CGFloat? = nil
static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) {
value = value ?? nextValue()
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论