swift 打开一个开关,关闭另外两个开关

yqkkidmi  于 2022-10-31  发布在  Swift
关注(0)|答案(2)|浏览(315)

我的应用程序出现问题。我尝试切换一个开关,当切换此开关时,所有其他开关都被切换为关闭。我尝试使用onChange方法。此方法适用于开关中的2个,但不适用于3个或更多?
下面是我尝试的代码:

import SwiftUI
import ToastUI

struct ContentView: View {
@State var generatedNumber : Int = 0

@State var allNumbers : Bool = true
@State var evensOnly : Bool = false
@State var oddsOnly : Bool = false

var body: some View {
    VStack {
        Text("Your genenerated number:")
            .font(.bold(.title)())

        Text("\(generatedNumber)")
            .font(.bold(.custom("Generated Number Size", size: 60))())
            .foregroundColor(.cyan)

        VStack{
            Toggle("All numbers", isOn: $allNumbers)
                .tint(.cyan)
                .onChange(of: allNumbers) { newValue in
                    //When toggled, turn other switches off, but leave this one on
                    evensOnly = !newValue
                    oddsOnly = !newValue
                }
            Toggle("Even numbers only", isOn: $evensOnly)
                .tint(.cyan)
                .onChange(of: evensOnly) { newValue in
                    allNumbers = !newValue
                    oddsOnly = !newValue
                }
            Toggle("Odd numbers only", isOn: $oddsOnly)
                .tint(.cyan)
                .onChange(of: oddsOnly) { newValue in

                    allNumbers = !newValue
                    evensOnly = !newValue
                }
        }.padding(30)
            .toggleStyle(.switch)
    }
}
}

这是我得到的:

一次只能打开一个开关,如果切换了另一个开关,则会关闭另外两个开关。执行此操作时,onChange方法会声明:“action trusted to update multiple times per frame.”这是否意味着两个@State重载试图在彼此太接近的执行时间发生?请帮助我

bkkx9g8r

bkkx9g8r1#

正如第一条评论所说的,你得到了一个保留周期。为了实现你的目标,有很多解决方案。但是,我会这样做(见代码片段),使用MVVM模式来实现它。

struct ContentView: View {
    @State var generatedNumber : Int = 0
    @StateObject var viewModel: ContentViewModel = .init()

    var body: some View {
        VStack {
            Text("Your genenerated number:")
                .font(.bold(.title)())

            Text("\(generatedNumber)")
                .font(.bold(.custom("Generated Number Size", size: 60))())
                .foregroundColor(.cyan)

            VStack {
                Toggle("All numbers", isOn: $viewModel.allNumbers)
                    .tint(.cyan)
                Toggle("Even numbers only", isOn: $viewModel.evensOnly)
                    .tint(.cyan)
                Toggle("Odd numbers only", isOn: $viewModel.oddsOnly)
                    .tint(.cyan)
            }.padding(30)
                .toggleStyle(.switch)
        }
    }
}

class ContentViewModel: ObservableObject {
    @Published var allNumbers : Bool = true
    @Published var evensOnly : Bool = false
    @Published var oddsOnly : Bool = false

    private var store: [AnyCancellable] = []

    init() {
        $allNumbers
            .sink(receiveValue: {
                guard $0 else { return }
                self.evensOnly = false
                self.oddsOnly = false
            })
            .store(in: &store)

        $evensOnly
            .sink(receiveValue: {
                guard $0 else { return }
                self.allNumbers = false
                self.oddsOnly = false
            })
            .store(in: &store)

        $oddsOnly
            .sink(receiveValue: {
                guard $0 else { return }
                self.allNumbers = false
                self.evensOnly = false
            })
            .store(in: &store)
    }
}
vc6uscn9

vc6uscn92#

这里有一个稍微可靠的答案,涉及到一个阵列,所以现在您哈弗一个动态的toggle视图。

enum numbersOptions: String {
                case all = "All numbers"
                case even = "Even numbers"
                case odd = "Odd numbers only"
            }

            struct OptionItem: Identifiable, Equatable {
                let id = UUID()
                let option: numbersOptions
                var isOn: Bool = false
            }

            struct ToggleTest: View {
                @State var generatedNumber : Int = 0
                @State var options = [OptionItem(option: .all, isOn: true), OptionItem(option: .even), OptionItem(option: .odd)]

                var body: some View {
                    VStack {
                        Text("Your genenerated number:")
                            .font(.bold(.title)())

                        Text("\(generatedNumber)")
                            .font(.bold(.custom("Generated Number Size", size: 60))())
                            .foregroundColor(.cyan)

                        VStack{
                            ForEach($options) { $option in

                                Toggle(option.option.rawValue, isOn: $option.isOn)
                                    .tint(.cyan)
                                    .onChange(of: option) { updated in

                                        if updated.isOn {
                                            self.options = self.options.map({
                                                var optionItem = $0
                                                optionItem.isOn = $0.id == updated.id
                                                return optionItem })

                                            // ANY UPDATED BASED ON THE SELECTED ITEM

                                            switch updated.option {
                                            case .all:
                                                print("all seleted")
                                            case .even:
                                                print("eve seleted")
                                            case .odd:
                                                print("odd seleted")
                                            }
                                        }
                                    }
                            }
                        }
                        .padding(30)
                        .toggleStyle(.switch)
                    }
                }
            }

相关问题