SwiftUI - AppStorage 不适用于 GeometryReader
SwiftUI - AppStorage doesn't work with GeometryReader
这是一个简单的例子。您可以创建新的 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 来完成。
- 正文。最后一个字应根据切换值切换 ON/OFF。这仅用于测试目的,以检查 AppStorage 是否正常工作。
- 切换 - 切换 onOff 变量并将其保存到 AppStorage(UserDefaults)。
AppStorage 仅在没有 GeometryReader 的情况下才能完美运行。请注释掉 3 行标记以查看。
这是一个错误吗?或者我的 AppStorage 代码有问题?或者 GeometryReader 部分可能是错误的?如果我可以将黄色部分设置为全角,我就可以完全放弃 GeometryReader。
是的,这绝对是一个错误。看起来 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,它在这种情况下工作正常。
在我的测试中有效的一个解决方案是分解出 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)
}
}
这是一个简单的例子。您可以创建新的 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 来完成。
- 正文。最后一个字应根据切换值切换 ON/OFF。这仅用于测试目的,以检查 AppStorage 是否正常工作。
- 切换 - 切换 onOff 变量并将其保存到 AppStorage(UserDefaults)。
AppStorage 仅在没有 GeometryReader 的情况下才能完美运行。请注释掉 3 行标记以查看。
这是一个错误吗?或者我的 AppStorage 代码有问题?或者 GeometryReader 部分可能是错误的?如果我可以将黄色部分设置为全角,我就可以完全放弃 GeometryReader。
是的,这绝对是一个错误。看起来 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,它在这种情况下工作正常。
在我的测试中有效的一个解决方案是分解出 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)
}
}