Home > Software design >  Changing text view - showing progress lengthy operation
Changing text view - showing progress lengthy operation

Time:07-16

I'm trying to show progress of a lengthy operation in a Text view. Using StateObject/Published var, I was hoping to see the Text change when the published var changes, however, I only see the last text appearing in the Text field. How can I dynamically change/update the Text field?

    @StateObject var tt = TestText()
    
    var body: some View {
        Text(tt.text)
            .padding()
            .onAppear(perform: { tt.ChangeText() })
    }
class TestText: ObservableObject {
    
    @Published var text = "text 0"
    
    func ChangeText() -> Void {
        sleep(3)         // some time-consuming stuff here
        text = "text 1"
        sleep(3)         // id
        text = "text 2"
        sleep(3)         // id
        text = "text 3"
        sleep(3)         // id
        text = "text 4"
        sleep(3)         // id
        text = "text 5"
    }
}

CodePudding user response:

your sleep(3) is wrong, it does not simulate a long time consuming task,
it stops everything (including the UI update) for 3 seconds. What you want is something like this to simulate a long time consuming task:

 struct ContentView: View {
    @StateObject var tt = TestText()
    
    var body: some View {
        Text(tt.text)
            .padding()
            .onAppear(perform: { tt.ChangeText() })
    }
}

 class TestText: ObservableObject {
     @Published var text = "text 0"
     
     func ChangeText() -> Void {
         DispatchQueue.main.asyncAfter(deadline: .now()   2) {
             self.text = "text 1"
         }
         DispatchQueue.main.asyncAfter(deadline: .now()   4) {
             self.text = "text 2"
         }
         DispatchQueue.main.asyncAfter(deadline: .now()   6) {
             self.text = "text 3"
         }
         DispatchQueue.main.asyncAfter(deadline: .now()   8) {
             self.text = "text 4"
         }
         DispatchQueue.main.asyncAfter(deadline: .now()   10) {
             self.text = "text 5"
         }
     }
 }

CodePudding user response:

Thanks for pointing me in the right direction. The sleep was just a placeholder for a lengthy operation, but the various operations run sequentially. With some slight modification to your code I achieve my intended goal. Now the code-bits run one after the other, showing the updated text after each step.

import Foundation

class TestText: ObservableObject {
    
    @Published var text = "text 0"
    
    func ChangeText() -> Void {
        DispatchQueue.main.asyncAfter(deadline: .now()   2) {
            self.DoSomething()
            self.text = "text 1"
            
            DispatchQueue.main.asyncAfter(deadline: .now()   0.1) {
                self.DoSomething()
                self.text = "text 2"
                
                DispatchQueue.main.asyncAfter(deadline: .now()   0.1) {
                    self.DoSomething()
                    self.text = "text 3"
                    
                    DispatchQueue.main.asyncAfter(deadline: .now()   0.1) {
                        self.DoSomething()
                        self.text = "text 4"
                        
                        DispatchQueue.main.asyncAfter(deadline: .now()   0.1) {
                            self.DoSomething()
                            self.text = "text 5"
                        }
                    }
                }
            }
        }
    }
    
    func DoSomething() -> Void {
        sleep(3)  // these are in fact various bits of codes, which have to run in sequence one after the other, DoSomething is just a placeholder for the moment
    }
}
  • Related