I have created a small ChatGPT clone using SwiftUI to communicate with his/her API. How I can create a print-style animation when the response comes from the API?
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
@State var text = ""
@State var models = [String]()
var body: some View {
VStack(alignment: .leading) {
ForEach($models, id: \.self) { $string in
Text(string)
}
Spacer()
HStack {
TextField("type here ...", text: $text)
Button("Send") {
send()
}
}
}
.onAppear {
viewModel.setup()
}
.padding()
}
private func send() {
guard !text.trimmingCharacters(in: .whitespaces).isEmpty else { return }
models.append("Me: \(text)")
viewModel.send(text: text) { response in
DispatchQueue.main.async {
self.models.append("ChatGPT: " + response)
self.text = ""
}
}
}
}
You can split text by words or letters, and then add it one by one. Here is an example.
struct ContentView: View {
@State private var letters: [String] = []
@State private var text: String = "I have created a small ChatGPT clone using SwiftUI to communicate with his/her API. How can I create a print-style animation when the response come from the API?"
@State private var displayText: String = ""
@State private var animating: Bool = false
var body: some View {
VStack {
Text(displayText)
.frame(height: 100)
.frame(maxWidth: .infinity, alignment: .leading)
Button(action: animate) {
Text("Animate")
.frame(maxWidth: .infinity)
.font(.headline)
.foregroundColor(.white)
.padding()
.background(animating ? .black.opacity(0.75) : .black)
.cornerRadius(12)
}
.disabled(animating)
}
.padding()
}
private func animate() {
animating = true
displayText = ""
letters = []
letters = Array(text).map { String($0) }
loop()
}
private func loop() {
let pace = 0.05
if !letters.isEmpty {
DispatchQueue.main.asyncAfter(deadline: .now() + pace) {
displayText += letters.removeFirst()
loop()
}
} else {
animating = false
}
}
}