Swiftui - Pass Data to Different Views

Passing Variables between Views SwiftUI

Create & pass in an environment object at the root view of your app, or where any 'children' views may need access to anytext. Store anytext as a @Published property in that ObservedObject.

That's a pointer, but there will be lots of similar questions and stuff. Here is a HWS article which may help.

Here is an example:

class MyModel: ObservableObject {
@Published var anytext = ""
}
struct ContentView: View {
@StateObject private var model = MyModel()

var body: some View {
Entry().environmentObject(model)
}
}

struct Entry: View {
@EnvironmentObject private var model: MyModel

var body: some View {
VStack {
TextField("Enter text here", text: $model.anytext)
.padding()
.border(Color.black, width: 1)
.padding()

TextDisplayer()
}
}
}

struct TextDisplayer: View {
@EnvironmentObject private var model: MyModel

var body: some View {
Text(model.anytext)
}
}

Result:

Result

All three views have model which they can access, to get the anytext property.

To answer your questions:

  1. You use @Published because String, Float, Double etc are all value types.

  2. Using environment objects, as shown here.

  3. They are not persisted, see @AppStorage for saving that.

SwiftUI - pass data to different views

You should use @EnvironmentObject. It allows an object to be shared, which is very important for sharing data to other views.

I am using a Shopping object in this example. This app will act like a shopping list. This whole project is available of GitHub here.

I really hope this is useful, as it took quite a while. This is just a general example of how to use @EnvironmentObject effectively between Views.

The app looks like this:

How the app looks



Creating the project

(can be downloaded through GitHub, see above link)

1: First, in your SceneDelegate.swift, replace:

let contentView = ContentView()

with:

let contentView = ContentView().environmentObject(Shopping())

2: Xcode will be complaining for now about Shopping not being made yet, so we will fix that next:

class Shopping: ObservableObject {

@Published var list = [
ShoppingItem("Bread", quantity: 1),
ShoppingItem("Milk", quantity: 2),
ShoppingItem("Eggs", quantity: 12)
]

func addItem(_ item: ShoppingItem) {
list.append(item)
}
}

class ShoppingItem: Identifiable {

var name: String
var quantity: Int

init(_ name: String, quantity: Int) {
self.name = name
self.quantity = quantity
}
}

3: Next, we want the main content, ContentView:

struct ContentView: View {

@EnvironmentObject private var shopping: Shopping
@State private var newItem: String?

var body: some View {
NavigationView {
List {
ForEach(shopping.list) { item in
NavigationLink.init(destination: EditView(currentItem: item)) {
HStack {
Text(item.name)
Spacer()
Text(String(item.quantity))
Spacer().frame(width: 10)
}
}
}

if newItem != nil {
TextField("New Item", text: $newItem.bound, onCommit: {
if !self.newItem!.isEmpty {
self.shopping.addItem(ShoppingItem(self.newItem!, quantity: 1))
}
self.newItem = nil
})
}
}
.navigationBarTitle("Shopping List")
.navigationBarItems(trailing: Button(action: {
self.newItem = ""
}, label: {
Image(systemName: "plus.circle.fill")
.resizable()
.frame(width: 25, height: 25)
}))
}
}
}

4: Along with this extension to let optional @States work (credit here, although this has been simplified):

extension Optional where Wrapped == String {

var bound: String {
get {
return self ?? ""
}
set {
self = newValue
}
}
}

5: And then finally - the EditView, to allow you to edit the name of the item in the shopping list:

struct EditView: View {

let currentItem: ShoppingItem
@EnvironmentObject private var shopping: Shopping
@State private var name = ""

var body: some View {
TextField("Item", text: $name, onCommit: saveName)
.padding()
.background(Color.gray)
.onAppear(perform: setName)
}

private func saveName() {
shopping.objectWillChange.send()
currentItem.name = name
}
private func setName() {
name = currentItem.name
}
}

How to pass data between SwiftUI views using NavigationLink

remove the second navigation view

struct SecondView: View {
var message: String
var body: some View {
VStack(spacing: 100 ) {
Text("\(message)")
NavigationLink(destination: ThirdView(message: self.message)) {
Text("Go to Third View")
}
}
}
}

struct ThirdView: View {
var message: String

var body: some View {

Text("\(message)")
}

}


SwiftUI Question passing a variable to another view

This is easily done with Bindings. Because mhzValue is marked with the @State property wrapper, it has an associated Binding. You can therefore declare a @Binding variable in your second view, and initialize it with the Binding to the original variable.

struct NextView : View {
@Binding var mhzValue: Float
...
}

When you specify NextView as the destination for your navigation button, pass it a Binding to mhzValue. (The dollar-sign syntax is a shorthand way to refer to the binding.)

struct ContentView : View {
@State private var mhzValue : Float = 0
...
NavigationButton(destination: NextView(mhzValue: self.$mhzValue)){...}
...
}

You can then use mhzValue inside NextView:

struct NextView : View {

@Binding var mhzValue: Float

var body: some View {
VStack{
Text("Display Slider Value Here:")
Text("\(Int(mhzValue)) Value")
.font(.title)
.fontWeight(.semibold)
.color(.blue)
}
}
}

Any changes you make to mhzValue within NextView will effectively be changes to ContentView.mhzValue.

SwiftUI: How to pass a data from one view and use it in the viewModel of another view

Use init and StateObject(wrappedValue:). Here is the possible solution.

Your view model

final class SubViewModel: ObservableObject {

@Published var phone = ""

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

Your subview

struct SubView: View {

@StateObject private var viewModel: SubViewModel
private let phone: String

init(phone: String) {
self.phone = phone
_viewModel = StateObject(wrappedValue: SubViewModel(phone: phone))
}

var body: some View {
ZStack {
Color.background
VStack {
Spacer()
// textfield default text should be the phone number passed from main view
TextField("type here...", text: $viewModel.phone)
Spacer()
}
}
}
}



Related Topics



Leave a reply



Submit