1

I have a list of strings I want to show to the user, sequentially. For example:

var array = ["Hey there!", "What's your name?"]

What I specifically want, is to show the first string for a few seconds and when that time passes, show the next.

Here's what I've done so far:

struct ContentView: View {
    @State private var array = ["Hey there!", "What's your name?"]

    var body: some View {
        VStack {
            TimedTextView(text: array.first, numberOfVisibilitySeconds: 3, onFinishedShowing: {
                self.array.removeFirst()
            })
        }
    }
}

And here’s TimedTextView:

struct TimedTextView: View {
    @State private var shouldMakeTextVisible = true

    var text: String!
    var numberOfVisibilitySeconds: Double!
    var onFinishedShowing: (() -> Void)!

    var body: some View {
        VStack {
            if shouldMakeTextVisible {
                Text(text)
                    .font(.largeTitle)
                    .transition(.asymmetric(insertion: .opacity, removal: .opacity))
                    .animation(.easeIn)
                    .onAppear(perform: {
                        DispatchQueue.main.asyncAfter(deadline: .now() + numberOfVisibilitySeconds) {
                            withAnimation {
                                self.shouldMakeTextVisible.toggle()
                            }
                        
                            self.onFinishedShowing()
                        }
                })
            }
        }
    }
}

As you can see, I'm using a closure to inform ContentView that the Text is done showing and to get the next one. But, what actually happens is that I see only the first string... Any idea what I’m doing wrong?

1 Answer 1

1

Here is a possible solution:

struct TimedTextContainer: View {
    @State private var currentIndex = 0
    @State private var isVisible = true

    let textArray: [String]

    var visibilityFor: TimeInterval
    var delay: TimeInterval

    var body: some View {
        if currentIndex < textArray.count, isVisible {
            Text(textArray[currentIndex])
                .font(.largeTitle)
                .id(currentIndex)
                .transition(.asymmetric(insertion: .opacity, removal: .opacity))
                .animation(.easeIn)
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + visibilityFor) {
                        withAnimation {
                            isVisible = false
                        }
                    }
                    DispatchQueue.main.asyncAfter(deadline: .now() + visibilityFor + delay) {
                        withAnimation {
                            currentIndex += 1
                            isVisible = true
                        }
                    }
                }
        }
    }
}
struct ContentView: View {
    let textArray = ["Hey there!", "What's your name?"]

    var body: some View {
        TimedTextContainer(textArray: textArray, visibilityFor: 3, delay: 1)
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Just perfect! Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.