我需要一些关于小型 SwiftUI 视图逻辑的帮助

I need some help for the logic of a small SwiftUI view

提问人:Alexnnd 提问时间:11/10/2023 更新时间:11/10/2023 访问量:58

问:

我有一个带有 3 个开关和 1 个按钮的视图。起初,所有的开关都是假的,你只能使一个开关为真。此外,该按钮仅在 和 之间存在差异时才有效。customOptionnewCustomOption

在可能的 4 种情况下,只有 2 种适用于我当前的代码:

1-您从所有开关开始,打开一个并确认。还行falsetrue

2-您从只有一个开关开始,进行并确认。还行truefalse

3-您从所有开关开始,打开一个开关,打开另一个开关,然后获得相应的值。不行falsetruetrueNone

4- 像 3 一样,但您已经打开了一个开关。不行true

我发现了问题:设置为在获得正确的值而不是相反的值之后,但我不知道如何解决它。有什么想法吗?newCustomOptionNone

import SwiftUI

struct ExampleView: View {
    @Environment(\.dismiss) private var dismiss
    @AppStorage("customOption") private var customOption = "None"
    @State private var newCustomOption = "None"
    @State private var optionOne = false
    @State private var optionTwo = false
    @State private var optionThree = false

    var body: some View {
        VStack {
            Toggle("Option One", isOn: $optionOne)
                .onAppear { load() }
                .onChange(of: optionOne) { _ in
                    newCustomOption = optionOne ? "optionOne" : "None"
                    print(newCustomOption)
                    if optionOne {
                        optionTwo = false
                        optionThree = false
                    }
                }
            Toggle("Option Two", isOn: $optionTwo)
                .onChange(of: optionTwo) { _ in
                    newCustomOption = optionTwo ? "optionTwo" : "None"
                    print(newCustomOption)
                    if optionTwo {
                        optionOne = false
                        optionThree = false
                    }
                }
            Toggle("Option Three", isOn: $optionThree)
                .onChange(of: optionThree) { _ in
                    newCustomOption = optionThree ? "optionThree" : "None"
                    print(newCustomOption)
                    if optionThree {
                        optionOne = false
                        optionTwo = false
                    }
                }
            Button("Confirm", action: { confirm() })
                .opacity(customOption == newCustomOption ? 0.5 : 1)
                .disabled((customOption == newCustomOption ? true : false))
        }
    }

    private func load() {
        newCustomOption = customOption
        switch newCustomOption {
        case "optionOne":
            optionOne = true
        case "optionTwo":
            optionTwo = true
        case "optionThree":
            optionThree = true
        default /* "None" */:
            return
        }
    }

    private func confirm() {
        customOption = newCustomOption
        dismiss()
    }
}

提前致谢!

swift swiftui 开关语句

评论

0赞 Benzy Neez 11/10/2023
我建议使用单选按钮而不是切换开关。请参阅 SwiftUI:如何在 SwiftUI 中实现单选按钮,了解实现方法。

答:

1赞 Joakim Danielson 11/10/2023 #1

我建议你改用一个,并将其样式化为单选按钮组,它将需要更少的代码和更简单的逻辑Picker

struct ExampleView: View {
    @Environment(\.dismiss) private var dismiss
    @AppStorage("customOption") private var customOption = "None"

    var body: some View {
        VStack {
            Picker(selection: $customOption, label: Text("Option:")) {
                Text("One").tag("optionOne")
                Text("Two").tag("optionTwo")
                Text("Three").tag("optionThree")
                Text("None").tag("None")
            }.pickerStyle(RadioGroupPickerStyle())

            Button("Dismiss") { dismiss() }
        }
    }
}

——

这是一个没有“无”选项的替代解决方案

struct ExampleView: View {
    @Environment(\.dismiss) private var dismiss
    @AppStorage("customOption") private var customOption: String = "None"
    @State private var selectedOption: String = "None"

    var body: some View {
        VStack { 

            Picker(selection: $selectedOption, label: Text("Option:")) {
                Text("One").tag("optionOne")
                Text("Two").tag("optionTwo")
                Text("Three").tag("optionThree")
            }.pickerStyle(RadioGroupPickerStyle())

            Button("Dismiss") {
                customOption = selectedOption
                dismiss()
            }
                .disabled(selectedOption == "None")
        }
        .onAppear { selectedOption = customOption }
    } 

}

——

下一步是改用枚举来保存不同的选项。

评论

0赞 Alexnnd 11/10/2023
是的,我知道,但我真的不想作为一种选择。我会坚持下去,但如果我没有找到任何解决方案,我将不得不使用“无线电选择器”选项。None
0赞 Joakim Danielson 11/10/2023
也许你应该在你的问题中更清楚地表明你不想要“无”。
0赞 Joakim Danielson 11/10/2023
我修改了我的答案,不包括“无”作为选项
0赞 Alexnnd 11/10/2023
实际上,您以前的解决方案是最好的。我别无选择,只能使用带选项。但最好的方法是使用或等价物来获得类似 Safari 的“历史”之类的东西。谢谢,我明天会试试这个。PickerNone.pickerStyle(.inline)
1赞 Benzy Neez 11/10/2023 #2

作为评论,我建议您使用单选按钮而不是切换来实现。如果您仅针对 macOS,则可以使用 (请参阅其他答案),但对于 iOS,您需要以不同的方式实现。RadioGroupPickerStyle

以下是如何使用 SwiftUI 答案中的 To be found 来完成:如何在 SwiftUI 中实现单选按钮(这是我的答案)。SelectionIndicator

  • 它开始时没有选择任何选项(= 无)。
  • 选择选项后,可以更改选择,但无法返回到无选择。
  • 可能的选项由枚举定义。如果你愿意,你可以用字符串来完成这一切,但我建议,如果选项都是预定义的,那么枚举会更干净(首先,没有错别字导致错误的可能性)。CustomOption
enum CustomOption: String {
    case none = "None"
    case one = "optionOne"
    case two = "optionTwo"
    case three = "optionThree"
}

struct ExampleView: View {
    @Environment(\.dismiss) private var dismiss
    @AppStorage("customOption") private var customOption = CustomOption.none.rawValue
    @State private var newCustomOption = CustomOption.none

    private func radioButtonItem(label: String, choice: CustomOption) -> some View {
        HStack {

            // see https://stackoverflow.com/a/75856182/20386264
            SelectionIndicator(isSelected: newCustomOption == choice)
            Text(label)
        }
        .onTapGesture {
            withAnimation { newCustomOption = choice }
        }
    }

    var body: some View {
        VStack(alignment: .leading) {
            radioButtonItem(label: "Option One", choice: .one)
            radioButtonItem(label: "Option Two", choice: .two)
            radioButtonItem(label: "Option Three", choice: .three)
            Button("Confirm", action: { confirm() })
                .opacity(newCustomOption.rawValue == customOption || newCustomOption == .none ? 0.5 : 1)
                .disabled(newCustomOption.rawValue == customOption || newCustomOption == .none)
        }
        .onAppear { load() }
    }

    private func load() {
        newCustomOption = CustomOption(rawValue: customOption) ?? .none
    }

    private func confirm() {
        customOption = newCustomOption.rawValue
        dismiss()
    }
}

评论

0赞 Alexnnd 11/10/2023
谢谢,我明天会检查这个。