(SwiftUI)如何在视图加载时隐藏文本并在点击切换后变得可见

(SwiftUI) How to make text hidden when view loads and become visible once toggle is tapped

我正在尝试使用 toggle 创建视图。切换更改 ui 首选项。更改切换时,它会更改下面的 Text。目前最简单的方法是

        VStack {
            Toggle("toggle me", isOn: $isOn)
            Text( isOn ? "I've been toggled once more" : "I've been toggled again" )
         }

我想要的是 Text( isOn ? "I've been toggled once more" : "I've been toggled again" ) 被隐藏,直到 开关被交互。打开或关闭它都没有关系,我想在与切换进行交互后使文本可见。我试过使用 .onChange(of: perform: )perform: 要求 ui res 一个无效的方法。所以我不能把文本放在那里。我已尝试使用 boolean/opacity 修复程序,如答案 中所示,但同样的问题。不能在执行中更改布尔值。只允许 void 方法。我确实尝试使用 onTapGesture 但那根本不起作用。我在那里有一份打印声明,从未打印过。不知道还能做什么。是否可以在与切换进行交互之前隐藏文本?这是我的代码

struct ProfileView: View {
    
    @State private var isOn = UserDefaults.standard.bool(forKey: "isOn")
    @State private var showText = false
    
    var body: some View {
        VStack { // vstack 0
            Text("Profile Page")
                .font(.title)
            
            Text("Are you ready to toggle?")
                .font(.title2)
                .multilineTextAlignment(.center)
            
            VStack { // vstack 1
                Toggle("toggle this", isOn: $isOn)
                    .onTapGesture {
                        print("toggled") // this never prints
                    }
//                    .onChange(of: isOn, perform: { value in
//                        value ? Text("yes") : Text("no")
//                        print("value = \(value)")
//                    })
// the Text here never shows up. and can't set showText = true here
                Text( isOn ? "Thank you." : "Toggled again" )
                    .opacity(showText ? 1 : 0)
// from the linked Whosebug answer. trying to make this boolean work. is it a lost cause? 
            } // vstack 1
        } // vstack 0
        .frame(
            width: UIScreen.main.bounds.width,
            height: UIScreen.main.bounds.height - 200,
            alignment: .top)
    }
}

所以我问的是可能的吗?感谢您的帮助!

您可以继续为 showText 使用 @State 变量,根据您的要求,只有在与 Toggle 进行交互时才会显示该变量。与其使用使用 UserDefaults 值初始化的 @State 变量,您可能希望对 isOn.

使用 @AppStorage
struct ProfileView: View {
    
    @AppStorage("isOn") private var isOn : Bool = false //@AppStorage syncs this value with UserDefaults automatically
    @State private var showText = false
    
    var body: some View {
        VStack { // vstack 0
            Text("Profile Page")
                .font(.title)
            
            Text("Are you ready to toggle?")
                .font(.title2)
                .multilineTextAlignment(.center)
            
            VStack { // vstack 1
                Toggle("toggle this", isOn: $isOn)
                    .onChange(of: isOn, perform: { value in
                        showText = true //Once the toggle is interacted with, set showText to true
                    })
                if showText { //only show the text if showText == true
                    Text( isOn ? "Thank you." : "Toggled again" )
                }
            } // vstack 1
        } // vstack 0
        .padding(.bottom, 200) //try not to use UIScreen dimensions in SwiftUI -- default to using padding instead when possible
    }
}

解决此问题的方法略有不同。您可以让 @AppStorage 存储一个可选值,只要您将可选值扩展到 符合RawRepresentable。这允许您消除 showText 状态变量,并允许您具有 3 种可能性的确定状态,true、false 和 nil。由于您不希望在 Toggle 被切换一次之前显示文本,因此 nil 状态可以让您知道这一点。一旦 Toggle 被切换,isOn 从那时起将有一个 true 或 false 值,除非你在其他地方再次将它设置为 nil。

这增加了一种复杂性。 Toggle 不带 Bool?。因此,您必须为其编写自己的绑定,以便将确定的值传递给 Toggle.

struct ProfileView: View {
    
    @AppStorage("isOn") private(set) var isOn: Bool? = nil

    var body: some View {
        VStack { // vstack 0
            Text("Profile Page")
                .font(.title)
            
            Text("Are you ready to toggle?")
                .font(.title2)
                .multilineTextAlignment(.center)
            
            VStack { // vstack 1
                Toggle("toggle this", isOn: Binding<Bool>(
                    get: { isOn ?? false },
                    set: { isOn = [=10=] }
                ))
                    .onTapGesture {
                        print("toggled") // this never prints
                    }
                Text( isOn == true ? "Thank you." : "Toggled again" )
                    // Compare isOn to nil, instead of use showText
                    .opacity(isOn != nil ? 1 : 0)
            } // vstack 1
            Spacer()
        } // vstack 0
        .padding()
    }
}

// This extension allows Optionals to be written to @AppStorage
extension Optional: RawRepresentable where Wrapped: Codable {
    public var rawValue: String {
        guard let data = try? JSONEncoder().encode(self),
              let json = String(data: data, encoding: .utf8)
        else {
            return "{}"
        }
        return json
    }

    public init?(rawValue: String) {
        guard let data = rawValue.data(using: .utf8),
              let value = try? JSONDecoder().decode(Self.self, from: data)
        else {
            return nil
        }
        self = value
    }
}