自从 swiftUI 2.0 出现以来,我一直无法根据在另一个模态呈现视图(设置视图)中所做的更改来更新视图。
我在主 ContentView 上显示一个字符串,该字符串从 SettingsView 上的分段 Picker 值派生其内容。问题是用户更改设置并丢弃 SettingsView 后,ContentView 中的字符串没有更新。身体没有重绘。
我正在使用@ObservableObject 和@StateObject 所以对它的每一次更改都应该触发重绘,但我不能让它工作......
我创建了一个符合 ObservableObject 协议的类:AppState 我正在使用该类来尝试传递数据,更重要的是,视图之间的数据更改,以便根据用户的设置重新绘制我的 ContentView。为了实例化这个类,我在我的 AppDelegate 文件中注册了一个 UserDefaults。
我还将组合框架导入到我的项目中,并在每个文件中添加了导入组合行!
为了说明问题,我尽可能地简化了我的代码,所以下面的内容可能看起来有点迂回,但它来自一个更复杂的应用程序,对此感到抱歉。
这是我的 ContentView 代码:
import SwiftUI
import Combine
struct ContentView: View {
@StateObject var appState: AppState
@State var modalViewCaller = 0 // used to present correct modalView
@State var modalIsPresented = false // to present the modal views
var body: some View {
let stringArray = generateString() // func to generate string according to user's pref
let recapString = stringArray[0]
return ZStack {
NavigationView {
VStack {
// MARK: - texts :
VStack {
Text(recapString)
.bold()
.multilineTextAlignment(/*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
} // end of VStack
.padding()
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color(UIColor.systemBlue), lineWidth: 4))
.padding()
} // END of VStack
.onAppear() {
self.modalViewCaller = 0
print("\n\n*********** Content View onAppear triggered ! ************\n")
}
.navigationBarTitle("DataFun", displayMode: .inline)
.navigationBarItems(leading: (
Button(action: {
self.modalViewCaller = 1 // SettingsView
self.modalIsPresented = true
}
) {
Image(systemName: "gear")
.imageScale(.large)
}
))
} // END of NavigationView
.onAppear() {
self.appState.updateValues()
}
} // End of ZStack
.sheet(isPresented: $modalIsPresented) {
sheetContent(modalViewCaller: $modalViewCaller, appState: AppState())
}
.navigationViewStyle(StackNavigationViewStyle())
}
// MARK: - struct sheetContent() :
struct sheetContent: View {
@Binding var modalViewCaller: Int // Binding to the @State modalViewCaller variable from ContentView
@StateObject var appState: AppState
var body: some View {
if modalViewCaller == 1 { // The settings view is called
SettingsView(appState: AppState())
.navigationViewStyle(StackNavigationViewStyle())
.onDisappear { self.modalViewCaller = 0 }
} else if modalViewCaller == 2 { // the "other view" is called
OtherView()
.navigationViewStyle(StackNavigationViewStyle())
.onDisappear { self.modalViewCaller = 0 }
}
}
} // END of func sheetContent
// MARK: - generateString()
func generateString() -> [String] {
var recapString = "" // The recap string
var myArray = [""]
// We create the recap string :
if UserDefaults.standard.integer(forKey: "rules selection") == 0 { // ICAO
recapString = "User chose LEFT"
} else if UserDefaults.standard.integer(forKey: "rules selection") == 1 { // AF Rules
recapString = "User chose RIGHT"
}
myArray = [recapString]
return myArray
} // End of func generateString()
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(appState: AppState())
}
}
这是我的 AppState 代码:
import Foundation
import SwiftUI
import Combine
class AppState: ObservableObject {
@Published var rulesSelection: Int = UserDefaults.standard.integer(forKey: "rules selection")
func updateValues() { // When the user changes a setting, the UserDefault is updated. Here, we align the AppState's value with what is now in the UserDefaults
self.rulesSelection = UserDefaults.standard.integer(forKey: "rules selection")
print("\nappState value (ruleSelection) updated from Appstate class func \"updateValues")
}
}
这是我的 SettingsView 代码:
import SwiftUI
import Combine
struct SettingsView: View {
@Environment(\.presentationMode) var presentationMode // in order to dismiss the Sheet
@StateObject var appState: AppState
@State private var rulesSelection = UserDefaults.standard.integer(forKey: "rules selection") // 0 is LEFT, 1 is RIGHT
var body: some View {
NavigationView {
VStack {
Spacer()
Text("Choose a setting below")
.padding()
Picker("", selection: $rulesSelection) {
Text("LEFT").tag(0)
Text("RIGHT").tag(1)
}
.pickerStyle(SegmentedPickerStyle())
.padding()
Spacer()
}
.navigationBarItems(
leading:
Button("Done") {
self.saveDefaults() // We set the UserDefaults
self.presentationMode.wrappedValue.dismiss() // This dismisses the view
// self.modalViewCaller = 0
}
) // END of NavBarItems
} // END of NavigationBiew
} // END of body
func saveDefaults() {
UserDefaults.standard.set(rulesSelection, forKey: "rules selection")
self.appState.updateValues() // This is a func from the AppState class that will align the appState's value to the UserDefaults
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView(appState: AppState())
}
}
如果有人有时间检查这个“现场”,还有一个工作项目:
https://github.com/Esowes/dataFun
感谢您的任何指示。
问候。