为什么此 SwiftUI 代码在目标屏幕中显示"Empty"?


struct ContentView: View {
@State var showModal = false
@State var text = "Empty"
var body: some View {
Button("show text") {
text = "Filled"
showModal = true
}
.sheet(isPresented: $showModal) {
VStack {
Text(text)
Button("print text") {
print(text)
}
}
}
}
}

我以为当点击"显示文本"按钮时,text的值将设置为"填充",showModal将设置为 true,以便显示sheet中指定的屏幕,并在该屏幕上显示"填充"一词。

我以为它会显示"已填充",但实际上它会显示"空"。

此外,当我使用print text按钮打印text时,控制台显示"已填充"。

为什么会这样工作?

当我点击目标屏幕上的按钮时,我缺少什么来显示我设置的值?

使用 Xcode12.4, Xcode12.5


添加新模式的代码。

struct ContentView: View {
@State var number = 0
@State var showModal = false

var body: some View {
VStack {
Button("set number 1") {
number = 1
showModal = true
print("set number = (number)")
}
Button("set number 2") {
number = 2
showModal = true
print("set number = (number)")
}
Button("add number") {
number += 1
showModal = true
print("add number = (number)")
}
}
.sheet(isPresented: $showModal) {
VStack {
let _ = print("number = (number)")
Text("(number)")
}
}
}
}

在上面的代码中,当我第一次点击"设置数字 1"或"设置数字 2"时,目标屏幕显示"0"。无论您点击同一按钮多少次,都会显示"0"。

但是,如果您在点击"设置数字2"后点击"设置数字 1",它将正常工作并显示"2"。如果您继续点击"设置数字 1",将显示"1",应用程序将正常工作。

当您在应用程序启动后首次点击"添加数字"时,仍会显示"0",但如果您再次点击"添加数字",将显示"2"并且应用程序将正确计数。

这表明即使更新了@State变量,也可以启动目标屏幕的渲染,但只有在目标屏幕中首先引用@State变量时,它似乎没有被正确引用。

谁能解释为什么它的行为是这样的?

或者这看起来像 SwiftUI 中的一个错误?

iOS 14开始,有几种主要呈现Sheet的方式

。首先,对于您的示例,您需要创建一个单独的View并将您的属性传递给Binding,然后在显示Sheet时正确更新。

// ContentView
Button { ... }
.sheet(isPresented: $showModal) {
SheetView(text: $text)
}
struct SheetView: View {
@Binding var text: String
var body: some View {
VStack {
Text(text)
Button("print text") {
print(text)
}
}
}
}

另一种方法是使用可识别Optional的对象,当该对象具有值时,将显示工作表。 这样,您就不需要单独管理工作表是否显示的状态。

struct Item: Identifiable {
var id = UUID()
var text: String
}
struct ContentView: View {
@State var item: Item? = nil
var body: some View {
Button("show text") {
item = Item(text: "Filled")
}
.sheet(item: $item, content: { item in
VStack {
Text(item.text)
Button("print text") {
print(item.text)
}
}
})
}
}

通过添加以下代码,我能够在目标屏幕中显示"已填充"一词。

  • updateDetector声明为 @State 变量。
  • 更新视图在工作表中显示的updateDetector
  • 在工作表的视图中的某处引用updateDetector
struct ContentView: View {
@State var showModal = false
@State var updateDetector = false
@State var text = "Empty"
var body: some View {
Button("show text") {
text = "Filled"
print("set text to (text)")
showModal = true
}
.sheet(isPresented: $showModal) {
let _ = print("render text = (text)")
VStack {
Text(text)
// use EmptyView to access updateDetector
if updateDetector {
EmptyView()
}
}
.onAppear {
// update updateDetector
print("toggle updateDetector")
updateDetector.toggle()
}
}
}
}

然后,在预加载时渲染初始值后,更新updateDetectoronSeem 的过程将起作用,视图将再次呈现,并显示@State变量的更新值。

当您点击上述代码中的"显示文本"按钮时,控制台中将显示以下内容,屏幕上将显示"已填充"。

set text to Filled
render text = Empty
toggle updateDetector
render text = Filled

我仍然不相信为什么我无法在第一个预加载的工作表中获取@State变量的更新值。因此,我将通过反馈助手向Apple报告此事。

最新更新