NEW: Learn to build amazing SwiftUI apps for macOS with my new book! >>

How to change a variable from another view

Forums > SwiftUI

Hello all,

my name is Kay and I am new to swiftui. I try to build my first countdown app with swiftui. Countdown is already working but I am not able to change the countdowntime from another view. I have 2 pickers on the other view and a save textfield which is a navigationlink. When I press the save textfield I want to save the total_min from the DetailView to the defaultTimeRemaing from the main view. I've searched the internet for solutions, but now I am more confused then before. I am not asking for code, just for giving me a hint where to start. Thanks in advance. Here is what I have so far:

//
//  ContentView.swift
//  Timepiece
//
//  Created by Pohl, Kay on 05.12.21.
//  Take care of your working time

import SwiftUI
import UserNotifications

//Variables
var defaultTimeRemaining: CGFloat = 5
let lineWidth: CGFloat = 15
let radius: CGFloat = 70

//##########################################################################
//Settingsview
//##########################################################################
struct DetailView: View {

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    @State var hours: Int = 1
    @State var minutes: Int = 0
    @State var hrs_min: Int = 0
    @State var total_min: Int = 0

    var body: some View {

        Text("Select your working time including breaks").foregroundColor(.gray).font(.title).multilineTextAlignment(.center).padding(20)

        HStack {

            Picker("", selection: $hours){
                ForEach(1..<11, id: \.self) { i in
                    Text("\(i) hours").tag(i)
                }
            }.pickerStyle(InlinePickerStyle()).frame(width: 250).clipped()
            Picker("", selection: $minutes){
                ForEach(0..<60, id: \.self) { i in
                    Text("\(i) minutes").tag(i)
                }
            }.pickerStyle(InlinePickerStyle()).frame(width: 250).clipped()

        }//.padding(.horizontal)
        NavigationLink(destination: ContentView()){
            Button(action:{ self.presentationMode.wrappedValue.dismiss()
                hrs_min = hours * 60
                total_min = hrs_min + minutes
                print(String(total_min))

            }){
                Text("Save").foregroundColor(.gray).font(.title3).padding(70)

            }

        }

    }

}

//##########################################################################
//Masterview
//##########################################################################
struct ContentView: View {

    //Define states
    @State var isActive = false
    @State var timeRemaining: CGFloat = defaultTimeRemaining
    @State var alert = false
    //Create timer
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    func simpleSuccess() {
        let generator = UINotificationFeedbackGenerator()
        generator.notificationOccurred(.success)
    }

    //#########
    //Main view
    //#########
    var body: some View {

        NavigationView{

            //Caption
            VStack(spacing: 60){
                HStack(){
                    VStack{
                        Text("Timepiece").font(.largeTitle).foregroundColor(.gray)
                        Text("").font(.subheadline).foregroundColor(.gray)

                    }
                }
                //Circle and time left
                ZStack{
                    Circle()
                        .stroke(Color.gray.opacity(0.2), style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))

                    Circle()
                        .trim(from: 0, to: 1 -
                              ((defaultTimeRemaining - timeRemaining) / defaultTimeRemaining))
                        .stroke(Color.green, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
                        .rotationEffect(.degrees(-90))
                        .animation(.easeInOut, value: 1)
                        .shadow(radius: 10)
                    VStack{
                        Text("\(Int(timeRemaining))")
                            .font(.largeTitle)
                            .bold()
                            .onLongPressGesture {
                                isActive = false
                                timeRemaining = defaultTimeRemaining
                                simpleSuccess()
                            }
                        Text("Minutes left").font(.subheadline).foregroundColor(.gray)

                    }

                }.frame(width: radius * 4, height: radius * 4, alignment: .center)

                //Start and Settings button
                VStack(spacing: 80){
                    Label("\(isActive ? "Pause" : "Start")", systemImage: "\(isActive ? "pause.fill" : "play.fill")").foregroundColor(.gray).font(.title).onTapGesture(perform: {isActive.toggle()})

                    NavigationLink(destination: DetailView()) {
                        Label("Settings", systemImage: "gearshape").foregroundColor(.gray).font(.subheadline).opacity(100)
                    }

                }

            }.onReceive(timer, perform: { _ in
                guard isActive else { return }
                if timeRemaining > 0 {
                    timeRemaining -= 1
                } else {
                    isActive = false
                    timeRemaining = defaultTimeRemaining
                }
            })
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
            DetailView()

        }
    }
}

1      

Okay, as you just wanted a hint what to look for I've got something for you: What is the @Binding property wrapper?

1      

@hatsushira!

Excellent hint.

1      

@Hatsushira Thanks for the hint. If I understand it correctly, the bound variable is changed immediately. That's not what I try to do. Only when I press the save button, the variable in the main view should change. I think I need to check for global variable?

Thanks Kay

1      

Yes. But you don't have to set it immediately. You can use a local variable in your DetailView set the bound variable to your local value in your Save action. So the bound variable wouldn't be changed when you don't click save.

1      

Ok, got it. That make sense. Tanks, will give it a try.

Kay

1      

For any reason, @binding didn't work. I got it working with @appstorage. But "coding" with copy and paste doesn't make sense. That's why I decided to stop this project and begin to learn the basics first.

Thanks for your help

Kay

1      

Sorry, to hear that. I did try it with your code and it worked for me. Perhaps, the call side for your DetailView was the obstacle.

I'm sure we can help you while you learn the basics. Paul has an excellent starter course. For me personally, Sean Allen has gread courses, too.

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Spend less time managing in-app purchase infrastructure so you can focus on building your app. RevenueCat gives everything you need to easily implement, manage, and analyze in-app purchases and subscriptions without managing servers or writing backend code.

Get Started

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.