I want to take 2 numbers input in the textField and print the multiplication of the two numbers in the third view(ResultView).
I have 3 views :-
a - ContentView(This view contains the navigation destination)
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
Button {
path.append("EnterNumberView")
} label: {
Text("Multiply")
}
.navigationDestination(for: String.self) { string in
switch string {
case "EnterNumberView":
EnterNumberView(path: $path)
case "ResultView":
ResultView()
default:
Text("Unknown")
}
}
}
}
}
b - EnterNumberView(Taking input two numbers)
struct EnterNumberView: View {
@Binding var path: NavigationPath
@State var input1: String = ""
@State var input2: String = ""
var calculation: String {
//check if both fields have text else no need for message
guard input1.isEmpty == false, input2.isEmpty == false else { return "" }
//check if both are numbers else we need to print "Error"
guard let m = Double(input1), let n = Double(input2) else { return "Error" }
let product = m * n
return String(format: "%.2f", product)
}
var body: some View {
VStack {
TextField("Enter First Number", text: $input1)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Enter Second Number", text: $input2)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button {
path.append("ResultView")
} label: {
Text("Tap to see result")
}
}
}
}
c - ResultView(I want to print the result here)
struct ResultView: View {
var body: some View {
Text("Your result is \(calculation)") //Cannot find calculation in scope
}
}
CodePudding user response:
You got 2 possibilities here:
create the result var in the
ContentView
and pass it along the same way you pass thepath
.or create a
ObservableObject
that holds you State that is passed allong into the environment.
This example shows a possible implementation with a Viewmodel
:
class Viewmodel: ObservableObject{
// these published values hold the state of your application
// and notify the view to refresh if something changed
@Published var input1: String = ""
@Published var input2: String = ""
@Published var result: String = ""
func calculation() {
//check if both fields have text else no need for message
guard input1.isEmpty == false, input2.isEmpty == false else { return }
//check if both are numbers else we need to print "Error"
guard let m = Double(input1), let n = Double(input2) else { return }
let product = m * n
result = String(format: "%.2f", product)
}
}
struct ContentView: View {
@State private var path = NavigationPath()
// create the viewmodel here
@StateObject private var viewmodel = Viewmodel()
var body: some View {
NavigationStack(path: $path) {
Button {
path.append("EnterNumberView")
} label: {
Text("Multiply")
}
.navigationDestination(for: String.self) { string in
switch string {
case "EnterNumberView":
EnterNumberView(path: $path)
// add the viewmodel to the environment
.environmentObject(viewmodel)
case "ResultView":
ResultView()
// add the viewmodel to the environment
.environmentObject(viewmodel)
default:
Text("Unknown")
}
}
}
}
}
struct EnterNumberView: View {
@Binding var path: NavigationPath
// pull the viewmodel from the environment
@EnvironmentObject private var viewmodel: Viewmodel
var body: some View {
VStack {
// reference the viewmodel input1 here
TextField("Enter First Number", text: $viewmodel.input1)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Enter Second Number", text: $viewmodel.input2)
.textFieldStyle(RoundedBorderTextFieldStyle())
// navigation
Button {
path.append("ResultView")
} label: {
Text("Tap to see result")
}
}
}
}
struct ResultView: View {
// pull the viewmodel from the environment
@EnvironmentObject private var viewmodel: Viewmodel
var body: some View {
// reference the result from the viewmodel
Text("Your result is \(viewmodel.result)")
.onAppear{
// perform calculation
viewmodel.calculation()
}
}
}