I have been battling with ChatGPT for almost two days, trying to get it to suggest a viable method of scrolling some text across its parent view (a Button) when the parent is focused.
It started off by suggesting the following approach:
import Kingfisher import SwiftUI struct VideoCard: View { @FocusState private var focusedIndex: Int? var body: some View { Button { // Handle button action } label: { VStack(spacing: 8) { KFImage(URL(string: "https://my-server.com/images/video-thumbnail.png")) .placeholder { ProgressView() }.resizable() ZStack { // Text inside a ZStack for smooth scrolling effect GeometryReader { geo in let textWidth = geo.size.width let containerWidth = 480.0 Text("This is a cool video!") .frame(width: containerWidth, alignment: .leading) .offset(x: focusedIndex == index ? -(textWidth - containerWidth) : 0) // Scroll left when focused .animation(focusedIndex != index ? .default : Animation.linear(duration: 3.0).repeatForever(autoreverses: false), value: focusedIndex) } } } }.focused($focusedIndex, equals: index) } } Which didn't work at all! So I asked it to try again multiple times, and it spat out several more versions of the same code, slightly-changed by each prompt (sometimes using .animation on the Text view itself and other times using withAnimation in a separate function), until it finally gave me this:
import Kingfisher import SwiftUI struct VideoCard: View { @FocusState private var focusedIndex: Int? @State var textWidth: CGFloat // Same code as above until... ZStack { Text(text).background(GeometryReader { geometry in Color.clear.onAppear { textWidth = geometry.size.width } }) // Same animation code } } Which worked, but the animation was way too fast, no matter how I tweaked the duration: value. So when I told it that, it suggested that I use a Timer instead, like so:
var textScrollTimer: Timer? func startScrollingText() { let scrollDistance = textWidth - 480.0 guard scrollDistance > 0 else { return } var scrollProgress = 0.0 // Stop any existing timer textScrollTimer?.invalidate() // Reset the scroll position textScrollPosition.scrollTo(x: 0) // Start a timer in 1 second to control the scrolling animation DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { textScrollTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true) { _ in if scrollDistance > scrollProgress { // Incrementally update the scroll position until we've reached the end scrollProgress += 2.0 textScrollPosition.scrollTo(x: scrollProgress) } else { // Stop the existing timer textScrollTimer?.invalidate() // Restart the animation with a new timer after 1 second DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { startScrollingText() } } } } } By this stage I had also moved my Text view into a ScrollView and bound its .scrollPosition() modifier to textScrollPosition.
This mostly worked, but I was getting weird concurrency issues, so now ChatGPT is suggesting that I go back to a withAnimation approach that is practically identical to its second suggestion over a day ago!
I've wasted so much time going around in circles and am so tired right now, I just want a quick and easy way of doing this, whether it involves a ScrollView or offset or whatever, I really don't care as long as it works!
MTIA for any helpful guidance :-)
