如何在 SwiftUI 中将我的环境对象设置为用户输入?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中将我的环境对象设置为用户输入?【英文标题】:How do I set my environment object to user input in SwiftUI? 【发布时间】:2021-02-16 11:36:01 【问题描述】:

我目前正在使用选项卡视图在我的项目中的 4 个视图之间导航,初始视图是我的 profileView,我希望用户在其中输入他们的信息和目标,例如年龄、身高等。**然而我是真的很难找到关于如何获取 用户输入 并将我的环境对象设置为该用户输入的良好示例和说明。我想只使用表单,但这似乎没有必要,而且我不太确定如何将环境对象更改为用户设置的对象。有没有人有任何好的文档可以参考我,或者向我展示如何获取用户输入并将我的环境对象设置为该数据的示例。 (我也不确定这是否有必要,因为我稍后也会将其存储在 userdefaults 或 coredata 中。

这是我的模型类,它是我的用户类数据。底部的设置值暂时忽略,项目后期开发时全部设置为空。

class UserInfoModel: ObservableObject 
    
    
    struct UserInfo: Identifiable 
        var id = UUID()
        var firstName: String
        var lastName: String
        var height: Int
        var weight: Int
        var gender: String
        var age: Int
        
    
    
    struct DailyCalorieGoals: Identifiable
        var id = UUID()
        var calorieGoal: Int
        var fatGoal: Int
        var proteinGoal: Int
        var carbGoal: Int

    
    
    struct CurrentCalorieProgress: Identifiable
        var id = UUID()
        var calorieProgress: Int
        var fatProgress: Int
        var carbProgress: Int
    
    
    @Published var personUserInfo = UserInfo.init(firstName: "", lastName:"", height: 0, weight: 0, gender: "", age: 0)
    @Published var personDailyCalorieGoals = DailyCalorieGoals.init(calorieGoal: 2400, fatGoal: 0, proteinGoal: 0, carbGoal: 0)
    @Published var personCurrentCalorieProgress = CurrentCalorieProgress.init(calorieProgress: 0, fatProgress: 0, carbProgress: 0)
    
   

那么当我在我的个人资料视图中时,我如何获取用户输入并将我的环境对象设置为该数据?

由于到目前为止提供的帮助,上述问题已经解决,但是使用下面链接的方法我得到以下内容,但我不确定如何将我的双环境对象的值更改为 fatInputString:

获取用户输入的新代码

Text("Fat: \(self.person.personDailyCalorieGoals.fatGoal, specifier: "%.0f")g")
                            
                            TextField("Enter new fat goal (g)", text: $fatInputString ).keyboardType(.numberPad)
                                .onReceive(Just(fatInputString))  newValue in
                                                let filtered = newValue.filter  "0123456789".contains($0) 
                                                if filtered != newValue 
                                                    self.fatInputString = filtered
                                                

但是我如何设置我的环境对象

self.person.personDailyCalorieGoals.fatGoal 

等于

self.inputString 

从上面的代码

【问题讨论】:

见Apple SwiftUI tutorial Handling User Input 【参考方案1】:

使用 Form 不是必需的——它只是让您的用户输入元素的格式在 ios/macOS 上更加标准化。

无论您是否使用Form,您都将使用各种用户输入元素并在您的UserInfoModel 上为它们分配绑定。 SwiftUI/Combine 使用 $ 运算符让这一切变得非常容易。

下面是一个如何获取几个字段输入的示例。可以看到,当字段信息发生变化时,值会反映在ContentView拥有的EnvironmentObject中——它会在EditorView上方的顶部显示值

struct ContentView : View 
    @ObservedObject var userInfo = UserInfoModel()
    
    var body: some View 
        VStack 
            Text("Name: \(userInfo.personUserInfo.firstName)")
            Text("Weight: \(userInfo.personUserInfo.weight)")
            Text("Carb: \(userInfo.personCurrentCalorieProgress.carbProgress)")
            EditorView().environmentObject(userInfo)
        
    


struct EditorView : View 
    @EnvironmentObject private var userInfo : UserInfoModel
    
    var body: some View 
        Form 
            TextField("First name", text: $userInfo.personUserInfo.firstName)
            Stepper("Weight", value: $userInfo.personUserInfo.weight, in: 0...500)
            Stepper("Carb progress", value: $userInfo.personCurrentCalorieProgress.carbProgress, in: 0...1000, step: 10)
        
    


基于 cmets 的更新: 编辑以显示您对数字文本输入的要求:

struct EditorView : View 
    @EnvironmentObject private var userInfo : UserInfoModel
    @State var fatInputString = "" //<-- Here
    
    var body: some View 
        Form 
            TextField("First name", text: $userInfo.personUserInfo.firstName)
            Stepper("Weight", value: $userInfo.personUserInfo.weight, in: 0...500)
            Stepper("Carb progress", value: $userInfo.personCurrentCalorieProgress.carbProgress, in: 0...1000, step: 10)
            Text("Fat: \(userInfo.personDailyCalorieGoals.fatGoal)g") //<-- Here
            TextField("Enter new fat goal (g)", text: $fatInputString ).keyboardType(.numberPad)
                .onReceive(Just(fatInputString))  newValue in
                    let filtered = newValue.filter  "0123456789".contains($0) 
                    if filtered != newValue 
                        self.fatInputString = filtered
                    
                    if let goal = Int(fatInputString), goal != userInfo.personDailyCalorieGoals.fatGoal   //<-- Here
                        userInfo.personDailyCalorieGoals.fatGoal = goal
                    
                
        
        
    

请注意,在您更新的代码中,您有一个错误,即脂肪量始终显示为 0。请务必查看带有 //&lt;-- Here 标记的每一行

【讨论】:

这是一个非常棒的答案,非常感谢!但是,我还有最后一个问题。如何让用户使用编辑文本或类似的东西来调整 int 值 $userInfo.personUserInfo.weight?谢谢! 在 TextField 中接受 Int 有一些非常好的答案(这需要一些摆弄):***.com/questions/58733003/… 如果您需要针对您的具体情况进行澄清,请告诉我。 好的,所以我能够获取用户的输入,但是在使用以下内容时出现以下错误: let fatInput = String(self.person.personDailyCaloriGoals.fatGoal) 然后尝试set TextField("Enter Fat", text: fatInput ) 您实际上并没有记下错误,但我假设它告诉您必须使用绑定,而不仅仅是 TextField 中的字符串。查看我链接到的答案以及它如何为此使用 @State 变量,并查看它使用的 $ 运算符。如果需要,您可以编辑此问题以显示您的代码,以便我提供更具体的建议。 刚刚编辑了我的答案,保留原始内容以防其他人需要它,非常感谢您迄今为止的帮助!

以上是关于如何在 SwiftUI 中将我的环境对象设置为用户输入?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中将 Firebase 结果转换为 List

在 SwiftUI 中将 swift 应用程序上的所有 Text() 设置为相同的颜色

SwiftUI:使用条件布局在画布中显示预览

如何在 SwiftUI 中将图像设置为按钮?

如何在 SwiftUI 中将自定义字体系列设置为整个应用程序的默认字体

如何在 SwiftUI 中将模糊效果作为背景?