简体   繁体   English

在 Swift/更好的方法中共享视图之间的数据?

[英]Sharing Data between Views in Swift/better approach for this?

I am brand new to Swift and SwiftUi, decided to pick it up for fun over the summer to put on my resume.我是 Swift 和 SwiftUi 的新手,决定在夏天把它拿来玩,把它放在我的简历上。 As a college student, my first idea to get me started was a Check calculator to find out what each person on the check owes the person who paid.作为一名大学生,让我开始的第一个想法是使用支票计算器来找出支票上的每个人对付款人的欠款。 Right now I have an intro screen and then a new view to a text box to add the names of the people that ordered off the check.现在我有一个介绍屏幕,然后是一个文本框的新视图,以添加订购支票的人的姓名。 I stored the names in an array and wanted to next do a new view that asks for-each person that was added, what was their personal total?我将姓名存储在一个数组中,然后想做一个新视图,询问每个添加的人,他们的个人总数是多少? I am struggling with sharing data between different structs and such.我正在努力在不同结构等之间共享数据。 Any help would be greatly appreciated, maybe there is a better approach without multiple views?任何帮助将不胜感激,也许没有多个视图有更好的方法? Anyways, here is my code (spacing a little off cause of copy and paste):无论如何,这是我的代码(与复制和粘贴的原因略有不同):

    import SwiftUI

struct ContentView: View {
    
    var body: some View {
        
        NavigationView {
            
            ZStack {
                
                Image("RestaurantPhoto1").ignoresSafeArea()
                
                VStack {
                    
                    Text("TabCalculator")
                        
                        .font(.largeTitle)
                        
                        .fontWeight(.bold)
                        
                        .foregroundColor(Color.white)
                        
                        .multilineTextAlignment(.center)
                        
                        .padding(.bottom, 150.0)
                    
                    
                    
                    NavigationLink(
                        
                        destination: Page2(),
                        
                        label: {
                            
                            Text("Get Started!").font(.largeTitle).foregroundColor(Color.white).padding().background(/*@START_MENU_TOKEN@*//*@PLACEHOLDER=View@*/Color.blue/*@END_MENU_TOKEN@*/)
                            
                        })
                }
                
            }
            
        }
        
    }
    
}



struct Page2: View {
    
    @State var nameArray = [String]()
    
    @State var name: String = ""
    
    @State var numberOfPeople = 0
    
    @State var personTotal = 0
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                
                TextField("Enter name", text: $name, onCommit: addName).textFieldStyle(RoundedBorderTextFieldStyle()).padding()
                List(nameArray, id: \.self) {
                    Text($0)
                }
            }
            
            .navigationBarTitle("Group")
        }
    }
    
    func addName() {
        
        let newName = name.capitalized.trimmingCharacters(in: .whitespacesAndNewlines)
        guard newName.count > 0 else {
            
            return
            
        }
        nameArray.append(newName)
        name = ""
        
    }
}


struct ContentView_Previews: PreviewProvider {
    
    static var previews: some View {
        
        Group {
            
            ContentView()
            ContentView()
            
        }
    }
}

You have multiple level for passing data between views in SwiftUI.在 SwiftUI 中的视图之间传递数据有多个级别。 Each one has its best use cases.每个都有其最佳用例。

  • Static init properties Static 初始化属性
  • Binding properties绑定属性
  • Environment Objects环境对象

Static init properties. Static 初始化属性。 You're probably used to that, it's just passing constants through your view init function like this:您可能已经习惯了,它只是通过您的视图 init function 传递常量,如下所示:

struct MyView: View {
    var body: some View {
        MyView2(title: "Hello, world!")
    }
}

struct MyView2: View {
    let title: String
    var body: some View {
        Text(title)
    }
}

Binding properties.绑定属性。 These enables you to pass data between a parent view and child.这些使您能够在父视图和子视图之间传递数据。 Parent can pass the value to the child on initialization and updates of this value and child view can update the value itself (which receives too).父级可以在初始化和更新该值时将值传递给子级,子视图可以更新值本身(也接收)。

struct MyView: View {
    // State properties stored locally to MyView
    @State private var title: String

    var body: some View {
        // Points the MyView2's "title" binding property to the local title state property using "$" sign in front of the property name.
        MyView2(title: $title)
    }
}

struct MyView2: View {
    @Binding var title: String
    var body: some View {
        // Textfield presents the same value as it is stored in MyView.
        // It also can update the title according to what the user entered with keyboard (which updates the value stored in MyView.
        TextField("My title field", text: $title)
    }
}

Environment Objects.环境对象。 Those works in the same idea as Binding properties but the difference is: it passes the value globally through all children views.这些工作原理与 Binding 属性相同,但不同之处在于:它通过所有子视图全局传递值。 However, the property is to be an "ObservableObject" which comes from the Apple Combine API.但是,该属性将是来自 Apple Combine API 的“ObservableObject”。 It works like this:它是这样工作的:

// Your observable object
class MyViewManager: ObservableObject {
    @Published var title: String

    init(title: String) {
        self.title = title
    }
}

struct MyView: View {
    // Store your Observable object in the parent View
    @StateObject var manager = MyViewManager(title: "")

    var body: some View {
        MyView2()
            // Pass the manager to MyView2 and its children
            .environmentObject(manager)
    }
}

struct MyView2: View {
    // Read and Write access to parent environment object
    @EnvironmentObject var manager: MyViewManager

    var body: some View {
        VStack {
            // Read and write to the manager title property
            TextField("My title field", text: $manager.title)
            MyView3()
                // .environmentObject(manager)
                // No need to pass the environment object again, it is passed by inheritance.
        }
    }
}

struct MyView3: View {
    @EnvironmentObject var manager: MyViewManager

    var body: some View {
        TextField("My View 3 title field", text: $manager.title)
    }
}

Hope it was helpful.希望对您有所帮助。 If it is, don't forget to mark this answer as the right one如果是,请不要忘记将此答案标记为正确答案

For others that are reading this to get a better understanding, don't forget to upvote by clicking on the arrow up icon对于正在阅读本文以获得更好理解的其他人,不要忘记通过单击向上箭头图标来投票

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM