swiftUI:在更改设置后更新文本
[编辑(1)以反映问题:。swiftUI:在更改设置后更新文本,swiftui,Swiftui,[编辑(1)以反映问题:。 [编辑(2):完全删除EnvironmentObject,应用程序现在可以工作了!不理解为什么正文会刷新,因为没有@State变量被修改…文本末尾的代码] 我正在编写一个应用程序,在某个时候,它会根据一组规则显示一些与2个数组的内容相关的文本。这些规则可以根据用户的偏好在设置视图中设置。 因此,当用户更改他希望在设置中应用的规则时,需要重新评估该文本。 当然,事情并没有那么容易。 我在主ContentView中将设置视图显示为模态,当我取消该模态时,ContentVi
[编辑(2):完全删除EnvironmentObject,应用程序现在可以工作了!不理解为什么正文会刷新,因为没有@State变量被修改…文本末尾的代码] 我正在编写一个应用程序,在某个时候,它会根据一组规则显示一些与2个数组的内容相关的文本。这些规则可以根据用户的偏好在设置视图中设置。 因此,当用户更改他希望在设置中应用的规则时,需要重新评估该文本。
当然,事情并没有那么容易。
我在主ContentView中将设置视图显示为模态,当我取消该模态时,ContentView的主体不会被重新绘制 我用@Published vars创建了一个EnvironmentObject,以跟踪所有用户首选项(也写入用户默认值),并将该@EnvironmentObject与我的ContentView和SettingsView共享,希望作为一个observedObject,它的更改将触发我的ContentView的刷新 不是这样 有什么办法可以帮我解决这个问题吗?任何指点都将不胜感激(再次!) 具有以下体系结构: 一个
appState
EnvironmentObject,一种
ContentView
,根据中设置的某些用户首选项显示一组文本
A设置视图
用户默认值在AppDelegate
中初始化
谢谢你在这方面的帮助
内容视图:
import SwiftUI
struct ContentView: View {
@State var modalIsPresented = false // The "settingsView" modally presented as a sheet
@State private var modalViewCaller = 0 // This triggers the appropriate modal (only one in this example)
var body: some View {
NavigationView {
VStack {
Spacer()
VStack {
Text(generateStrings().text1)
.foregroundColor(Color(UIColor.systemGreen))
Text(generateStrings().text2)
} // end of VStack
.frame(maxWidth: .infinity, alignment: .center)
.lineLimit(nil) // allows unlimited lines
.padding(.all)
Spacer()
} // END of main VStack
.onAppear() {
self.modalViewCaller = 0
}
.navigationBarTitle("Test app", displayMode: .inline)
.navigationBarItems(leading: (
Button(action: {
self.modalViewCaller = 6 // SettingsView
self.modalIsPresented = true
}
) {
Image(systemName: "gear")
.imageScale(.large)
}
))
} // END of NavigationView
.sheet(isPresented: $modalIsPresented, content: sheetContent)
.navigationViewStyle(StackNavigationViewStyle()) // This avoids dual column on iPad
} // END of var body: some View
// MARK: @ViewBuilder func sheetContent() :
@ViewBuilder func sheetContent() -> some View {
if modalViewCaller == 6 {
SettingsView()
}
} // END of func sheetContent
// MARK: generateStrings() : -
func generateStrings() -> (text1: String, text2: String, recapText: String, isHappy: Bool) { // minimumNumberOfEventsCheck
var myBool = false
var aString = "" // The text 1 string
var bString = "" // The text 2 string
var cString = "" // The recap string
if UserDefaults.standard.bool(forKey: kmultiRules) { // The user chose the dual rules option
let ruleSet = UserDefaults.standard.integer(forKey: kruleSelection) + 1
aString = "User chose 2 rules option"
bString = "User chose rule set # \(ruleSet)"
myBool = true
print("isDualRules true loop : generateStrings was called at \(Date().debugDescription)")
cString = "Dual rules option, user chose rule set nb \(ruleSet)"
}
else // The user chose the single rule option
{
aString = "User chose single rule option"
bString = "User had no choice : there is only one set of rules !"
myBool = false
print("isDualRules false loop : generateStrings was called at \(Date().debugDescription)")
cString = "Single rule option, user chose nothing."
}
return (aString, bString, cString, myBool)
} // End of func generatestrings() -> String
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
return ContentView()
}
}
设置视图:
import SwiftUI
import UIKit
struct SettingsView: View {
@Environment(\.presentationMode) var presentationMode // in order to dismiss the Sheet
@State public var multiRules = UserDefaults.standard.bool(forKey: kmultiRules)
@State private var ruleSelection = UserDefaults.standard.integer(forKey: kruleSelection) // 0 is rule 1, 1 is rule 2
var body: some View {
NavigationView {
List {
Toggle(isOn: $multiRules)
{
Text("more than one rule ?")
}
.padding(.horizontal)
if multiRules {
Picker("", selection: $ruleSelection){
Text("rules 1").tag(0)
Text("rules 2").tag(1)
}.pickerStyle(SegmentedPickerStyle())
.padding(.horizontal)
}
} // End of List
.navigationBarItems(
leading:
Button("Done") {
self.saveDefaults() // We try to save once more if needed
self.presentationMode.wrappedValue.dismiss() // This dismisses the view
}
)
.navigationBarTitle("Settings", displayMode: .inline)
} // END of Navigation view
} // END of some View
func saveDefaults() {
UserDefaults.standard.set(multiRules, forKey: kmultiRules)
UserDefaults.standard.set(ruleSelection, forKey: kruleSelection)
}
}
// MARK: Preview struct
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
return SettingsView()
}
}
常量.swift文件:
import Foundation
import SwiftUI
let kmultiRules = "two rules"
let kruleSelection = "rules selection"
let kappStateChanged = "appStateChanged"
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UserDefaults.standard.register(defaults: [ // We initialize the UserDefaults
"two rules": false,
"rules selection": 0, // 0 is ruel 1, 1 is rule 2
"appStateChanged": false
])
return true
}
如果在两个视图中有一个共享的@EnvironmentObject和@Published属性,如果从一个视图中更改此类属性,则另一个视图将重新执行body属性,并且该视图将更新 创建简单的独立示例确实很有帮助——不仅是为了在这里提问,也为了获得更深入的理解/了解为什么它在复杂情况下不起作用 例如:
导入快捷界面
类文本设置:ObservableObject{
@已发布变量计数:Int=1
}
结构文本设置视图:视图{
@环境对象变量设置:文本设置
var body:一些观点{
形式{
选择器(选择:$settings.count,标签:
文本(“文本重复计数”))
{
ForEach(数组(1…5),id:\.self){中的值
文本(字符串(值)).tag(值)
}
}
}
}
}
结构文本和设置示例视图:视图{
@环境对象变量设置:文本设置
var body:一些观点{
文本(字符串(重复“Hello”,计数:Int(settings.count)))
.navigationBarItems(尾部:NavigationLink(“设置”,目标:TextSettingsView()))
}
}
带有设置示例视图的结构文本\u预览:预览提供程序{
静态var预览:一些视图{
导航视图{
TextWithSettingExampleView()
}
.environmentObject(TextSettings())
}
}
我不确定自己是否完全理解这个问题,但我认为可能存在类似的问题,即当从模式触发更改时,我从未让contentview反映观察对象中的更新。我通过在我观察到的对象中触发一个动作来解决/破解了这个问题,当时我忽略了模态,如下所示:
struct ContentView: View {
//
@State var isPresentingModal = false
var body: some View {
//
.sheet(isPresented: self.$isPresentingModal) {
PresentedModalView()
.onDisappear {
//Do something here
}
}
}
}
让我们从问题的演示代码开始…阅读并记录这个和这个。这不是一个“我们免费为您编写代码”的平台,而是一个“我们帮助您完成您迄今为止所获得的代码”的平台。好吧,我从来没有认为这个平台像是一个“免费代码”的场所。我总是提供清晰的代码来说明我的任何问题。我只是在这里找一个指针。。。我的应用程序的代码现在太长了,我很难提取一个工作框架来提供代码。明天将调查通知中心,这似乎对我的问题很有希望。尝试了通知中心的方法,在OnDiss中触发它,正如Olaf建议的那样,没有乐趣。。。我最大限度地简化了应用程序,并将其发布在GitHub上,如果有人有时间花在这上面。。。谢谢与onAppear相反,onDisappear总是被触发的好主意。但是文本仍然不会更新!我用一个链接编辑了我的问题,该链接指向我通过尽可能简化现有应用程序而创建的示例应用程序:浏览一下您的项目,您是否尝试过在内容视图中从onDisappear调用“self.appState.updateValues()”?只是胡乱猜测。是的,我猜了,不高兴。。。我完全解构了我的应用程序,为了摆脱环境对象,我将generateStrings func中的if参数更改为direct UserDefaults值,现在,我的ContentView的主体被刷新,即使没有修改@State变量!简言之,这个应用程序可以工作,但我不知道为什么。。。将用我的代码编辑问题…感谢您的洞察力Ralf,我更新了我的问题:我构建了一个示例项目(),但仍然无法使其工作。我正在更改环境对象的@Published属性,未成功。。。