Home > Software design >  Keeping text on TextEditor element while switching views SwiftUI
Keeping text on TextEditor element while switching views SwiftUI

Time:10-17

Well, I'm working on a little app where I have a TextEditor element to type whatever we want. The case is, I want to keep the text on the TextEditor while switching other views, but I can't.

TextEditor before switching the view : TextEditor before switching the view

TextEditor after switching the view : TextEditor after switching the view

The code is the next one:

    struct VistaDatos: View {
    
    @State private var opinion: String = ""

    
    var progreso : Double {
        Double(opinion.count)
    }
    
    var body: some View {
         
        VStack{ 
        //SOME CODE HERE ...
            HStack{
                Text("Mi opinión...")
                    .font(.headline)
                Image(systemName: "pencil")
                    .foregroundColor(.white)
                    .font(.headline)
            }
            
            VStack{
                TextEditor(text: $opinion)
                    .background(.green)
                    .frame(width: 350, height: 250)
                    .background().colorMultiply(.green)
                    .overlay(Rectangle().stroke(Color.black, lineWidth:2))
                    .disableAutocorrection(true)
                    .onChange(of: self.opinion) { value in
                        if Int(opinion.count) > 150 {
                            self.opinion = String(value.prefix(150))
                        }
                    }
                
                Text("Número de palabras: \(Int(progreso))/150").foregroundColor(Int(progreso) >= 100 ? .red : .white)
                ProgressView(,value: progreso, total: 150) {
                }.frame(width: 350, alignment: .center)
            }
        }.background(Color.green)
        Spacer()
    }
}

I have to use .onDisappear event to make it work (it seems to be on the first level stack ), but it isn't working... How can I make it work?

Thanks in advance.

CodePudding user response:

Since you say you have multiple views, that I assume may need the opinion text, try this example code. It keeps your text in a ObservableObject, that you can use throughout your app.

For you to do, is to code the save and retrieve from wherever you want. In this example it is using the UserDefaults.

class StoreService: ObservableObject {
    // your text
    @Published var opinion = ""
    
    // ... todo code to store your data when you are finished
    func save() {
        // save your data
        UserDefaults.standard.set(opinion, forKey: "opinion")
    }
    
    // ... todo code to retrieve your data when the app starts again
    init() {
        // get your data
        opinion = UserDefaults.standard.string(forKey: "opinion") ?? ""
    }
}

struct ContentView: View {
    @StateObject var store = StoreService() // <-- here
    
    var body: some View {
        NavigationStack {
            VStack (spacing: 50) {
                Text("\(store.opinion.count) characters typed")
                NavigationLink("go to VistaDatos", value: "editor")
                    .navigationDestination(for: String.self) { str in
                        VistaDatos()
                    }
            }
        }.environmentObject(store) // <-- here
    }
}

struct VistaDatos: View {
    @EnvironmentObject var store: StoreService  // <-- here

    var progreso : Double {
        Double(store.opinion.count)
    }
    
    var body: some View {
        
        VStack{
            //SOME CODE HERE ...
            HStack{
                Text("Mi opinión...").font(.headline)
                Image(systemName: "pencil")
                    .foregroundColor(.white)
                    .font(.headline)
            }
            
            VStack{
                TextEditor(text: $store.opinion)  // <-- here
                    .background(.green)
                    .frame(width: 350, height: 250)
                    .background().colorMultiply(.green)
                    .overlay(Rectangle().stroke(Color.black, lineWidth:2))
                    .disableAutocorrection(true)
                    .onChange(of: store.opinion) { value in
                        if store.opinion.count > 150 {
                            store.opinion = String(value.prefix(150))
                        }
                    }
                
                Text("Número de palabras: \(Int(progreso))/150").foregroundColor(Int(progreso) >= 100 ? .red : .white)
                
                ProgressView(value: progreso, total: 150).frame(width: 350, alignment: .center)
                
                Button("Save me") {  // <-- here
                    store.save()
                }
            }
        }.background(Color.green)
        Spacer()
    }
}

Alternatively, you could use the simple @AppStorage, like this:

struct ContentView: View {
    @AppStorage("opinion") var opinion = ""  // <-- here
    
    var body: some View {
        NavigationStack {
            VStack (spacing: 50) {
                Text("\(opinion.count) characters typed")
                NavigationLink("go to VistaDatos", value: "editor")
                    .navigationDestination(for: String.self) { str in
                        VistaDatos()
                    }
            }
        }
    }
}

struct VistaDatos: View {
    @AppStorage("opinion") var opinion = ""  // <-- here

    var progreso : Double {
        Double(opinion.count)
    }
    
    var body: some View {
        
        VStack{
            //SOME CODE HERE ...
            HStack{
                Text("Mi opinión...").font(.headline)
                Image(systemName: "pencil")
                    .foregroundColor(.white)
                    .font(.headline)
            }
            
            VStack{
                TextEditor(text: $opinion) // <-- here
                    .background(.green)
                    .frame(width: 350, height: 250)
                    .background().colorMultiply(.green)
                    .overlay(Rectangle().stroke(Color.black, lineWidth:2))
                    .disableAutocorrection(true)
                    .onChange(of: opinion) { value in
                        if opinion.count > 150 {
                            opinion = String(value.prefix(150))
                        }
                    }
                
                Text("Número de palabras: \(Int(progreso))/150").foregroundColor(Int(progreso) >= 100 ? .red : .white)
                
                ProgressView(value: progreso, total: 150).frame(width: 350, alignment: .center)
            }
        }.background(Color.green)
        Spacer()
    }
}
  • Related