SwiftUI - AppStorage 不适用于 GeometryReader
Posted
技术标签:
【中文标题】SwiftUI - AppStorage 不适用于 GeometryReader【英文标题】:SwiftUI - AppStorage doesn't work with GeometryReader 【发布时间】:2021-09-06 11:30:58 【问题描述】:这是一个简单的例子。您可以创建新的 SwiftUI ios 项目并将其复制到 ContentView 文件中。
import SwiftUI
struct Settings
static let onOff = "onOff"
struct ContentView: View
@AppStorage(wrappedValue: false, Settings.onOff) var onOff
var body: some View
NavigationView
GeometryReader reader in // < Comment out this line
List
Section (header:
VStack
HStack
Spacer()
VStack
Text("THIS SHOULD BE FULL-WIDTH")
Text("It is thanks to GeometryReader")
Spacer()
.padding()
.background(Color.yellow)
HStack
Text("This should update from AppStorage: ")
Spacer()
Text(onOff == true ? "ON" : "OFF")
.padding()
.frame(width: reader.size.width) // < Comment out this line
.textCase(nil)
.font(.body)
)
Toggle(isOn: $onOff)
Text("ON / OFF")
.listStyle(GroupedListStyle())
// < Comment out this line
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
我有 3 个元素:
-
带有黄色背景的文本 - 我需要它是全角的,我使用 GeometryReader 来完成。
文本。最后一句话应该根据切换值打开/关闭。这仅用于测试目的,以检查 AppStorage 是否正常工作。
Toggle - 切换 onOff 变量并将其保存到 AppStorage (UserDefaults)。
AppStorage 只有在没有 GeometryReader 的情况下才能完美运行。请注释掉 3 个标记的行以查看。
这是一个错误吗?还是我的 AppStorage 代码有问题?或者 GeometryReader 部分是错误的?如果我可以将黄色部分设置为全角,我可以完全放弃 GeometryReader。
【问题讨论】:
【参考方案1】:在我的测试中有效的一个解决方案是排除GeometryReader
的内容,包括@AppStorage
:
struct ContentView: View
var body: some View
NavigationView
GeometryReader proxy in
_ContentView(width: proxy.size.width)
struct _ContentView: View
var width: CGFloat
@AppStorage(wrappedValue: false, Settings.onOff) var onOff
var body: some View
List
Section(header: header)
Toggle(isOn: $onOff)
Text("ON / OFF")
.listStyle(GroupedListStyle())
var header: some View
VStack
VStack
Text("THIS SHOULD BE FULL-WIDTH")
Text("It is thanks to GeometryReader")
.padding()
.frame(width: width)
.background(Color.yellow)
HStack
Text("This should update from AppStorage: ")
Spacer()
Text(onOff == true ? "ON" : "OFF")
.padding()
.textCase(nil)
.font(.body)
【讨论】:
谢谢,罗伯!它有效:) 所以它似乎是一个错误。 GeometryReader 或 AppStorage 在 SwiftUI 中数据流的工作方式存在一些问题。您的解决方案会强制视图正确刷新。我会将这个错误提交给 Apple。用你的解决方案。非常感谢【参考方案2】:是的,这绝对是一个错误。看起来AppStorage
由于某种原因与State
的行为不完全相同,并且更改不会触发GeometryReader
内部的更新。示例可以简化为:
struct ContentView: View
@AppStorage("onOff") var onOff = false
var body: some View
VStack
Text("Text updating: " + (onOff == true ? "ON" : "OFF"))
GeometryReader reader in
Toggle(isOn: $onOff)
Text("Text not updating: " + (onOff == true ? "ON" : "OFF"))
这在最新的 iOS 15 测试版中甚至都没有修复。您可以尝试使用一些重复的状态变量来破解,但我建议您切换到 custom AppStorage,它在这种情况下可以正常工作。
【讨论】:
谢谢你,菲利普。我不知道自定义 AppStorage。感谢您的链接。到目前为止,我正在尝试编写一个没有任何依赖关系的代码,所以我想我会提出你的其他建议 - 使用另一个状态变量。但现在 Rob 的解决方案同样有效。 @mallow 我明白了。我不喜欢使用一些巨大的依赖项,但在这种情况下,解决方案源代码只有大约 60 行代码(其余的只是不同类型的样板初始化程序),这对我来说很好。如果需要,我可以轻松地复制和修改它,这与系统不同,并且不需要通过将GeometryReader
移出视图来破解它。但这取决于你。
在我的情况下,移动 GeometryReader 更容易,因为我只有一个地方。除了这个 AppStorage 对我有用。但是很高兴您发布了此链接,因为在其他项目中您的解决方案可能会更好。此外,我对外部库和 Swift 包还没有太多经验:)以上是关于SwiftUI - AppStorage 不适用于 GeometryReader的主要内容,如果未能解决你的问题,请参考以下文章
使用 @AppStorage 进行设置的 SwiftUI 最佳实践:如何在加载 @AppStorage 之前读取 UserDefaults?