首页 > 解决方案 > 为什么此 SwiftUI 代码在目标屏幕中显示“空”?

问题描述

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并显示“已填充”字样屏幕。

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

此外,当我text使用print 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)")
            }
        }
    }
}

在上面的代码中,当我第一次点击“set number 1”或“set number 2”时,目标屏幕显示“0”。无论您点击同一个按钮多少次,都会显示“0”。

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

应用程序启动后第一次点击“加号”时,仍会显示“0”,但再次点击“加号”时,将显示“2”,应用程序会正确计数。

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

谁能解释它为什么会这样?

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

标签: swiftui

解决方案


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

首先,对于您的示例,您需要创建一个单独的View并将您的属性传递给 a 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)
                }
            }
        })
    }
}

推荐阅读