我有一个视图与语言切换列表,应该在重新启动后改变当前的应用程序语言。我知道如何用按钮创建这个功能,但它与切换器的工作方式不同。我试过使用on change,但它不允许在第二次点击后关闭开关。如何正确地做到这一点?
struct Languages: View {
@State private var currentLanguage = true
@State private var currentLanguageEnglish = true
@State private var currentLanguageRussian = false
@State private var showingAlert = false
@Environment(.presentationMode) var mode: Binding<PresentationMode>
@State var currentSysLanguage = UserDefaults.standard.string(forKey: "language")
var body: some View {
VStack(alignment: .leading) {
DoubleTextView(topText: LocalizedStringKey("languages"), buttomText: "", topTextSize: 24, buttomTextSize: 0)
// Works just right, wrong design.
Button("English", action: {
currentSysLanguage = "en"
UserDefaults.standard.set(currentSysLanguage, forKey: "language")
showingAlert.toggle()
})
.alert("Restart your app", isPresented: $showingAlert) {
Button("OK", role: .cancel) { }
}
Button("French", action: {
currentSysLanguage = "fr"
UserDefaults.standard.set(currentSysLanguage, forKey: "language")
showingAlert.toggle()
})
.alert("Restart your app", isPresented: $showingAlert) {
Button("OK", role: .cancel) { }
}
// Does not work, this is how it should be.
ZStack(alignment: .top) {
Toggle(isOn: $currentLanguageEnglish) {
Text("English")
.font(.custom("Manrope-Bold", size: 16))
.foregroundColor(.white)
}
.padding(.horizontal)
.tint(Color("active"))
}
.padding(.vertical, 30.0)
.background(Rectangle()
.fill(Color("navigation"))
.frame(height: 50)
.cornerRadius(8))
ZStack(alignment: .top) {
Toggle(isOn: $currentLanguageRussian) {
Text("French")
.font(.custom("Manrope-Bold", size: 16))
.foregroundColor(.white)
}
.padding(.horizontal)
.tint(Color("active"))
}
.background(Rectangle()
.fill(Color("navigation"))
.frame(height: 50)
.cornerRadius(8))
Spacer()
}
.background(
Image("background2")
.resizable()
.scaledToFill()
.edgesIgnoringSafeArea(.all)
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
)
.onChange(of: currentLanguageEnglish, perform: { newValue in
currentLanguageRussian = true
})
.onChange(of: currentLanguageRussian, perform: { newValue in
currentLanguageEnglish = true
})
.padding(.top, 40)
.overlay {
HStack {
Spacer()
Button {
self.mode.wrappedValue.dismiss()
} label: {
HStack {
Image(systemName: "arrow.left")
.foregroundColor(.white)
.font(.system(size: 24))
Spacer()
}
}
}
.padding(.horizontal, 3.0)
.frame(maxHeight: .infinity, alignment: .top)
}
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
.padding(.horizontal, 10.0)
}
}
有许多方法可以完成类似的事情,其中一种方法是将切换绑定到自定义绑定对象:
Toggle(isOn: .init(get: {
currentSysLanguage == "en"
}, set: { isOn in
currentSysLanguage = isOn ? "en" : defaultLanguage
})) {
Text("English")
}
这里getter使toggle监听currentSysLanguage == "en"
。它将根据语句的计算结果是否为真而打开/关闭。而当手动拨动setter时,将触发setter,并将currentSysLanguage
设置在"en"
和defaultLanguage
之间。
注意,我已经添加了defaultLanguage
来表示所有开关都关闭时的状态。
然后,您可以通过更改与之比较的语言代码,使用相同的代码创建尽可能多的切换。
接近尾声时,您将添加一个.onChange
修饰符来侦听currentSysLanguage
以将更改发送到UserDefaults
:
.onChange(of: currentSysLanguage, perform: { newValue in
UserDefaults.standard.set(newValue, forKey: "language")
})