0

I have a list of names that appear vertically thanks to an animation, I would like to have auto-scroll when a new name appears but i don't know how to go on...I saw some questions like this but all of them were a 'jump to a number' solution, not progressively scroll...any suggestions?

enter image description here

UPDATED CODE:

struct ContentView: View {
    let correctNames = ["Steve", "Bill", "John", "Elon", "Michael", "Justin", "Marcell", "David", "Gabriel", "Eric", "Jeffrey", "Taylor", "Jennifer", "Christian"]
    @State private var animating = false
    
    var body: some View {
        VStack {
            ScrollView(showsIndicators: false) {
                ForEach(0..<correctNames.count, id: \.self) { index in
                    Text("\(correctNames[index])")
                        .font(.system(size: 60))
                        .opacity(animating ? 1 : 0)
                        .animation(.easeIn(duration: 0.5).delay(Double(index) * 0.2), value: animating)
                }
            }
        }
        .onAppear {
            animating.toggle()
        }
    }
}
jooh
  • 105
  • 7
  • 1
    Use scroll view reader is the closet thing in SwiftUI. Using UIKit you can be more meticulous, there isn’t anything built in – lorem ipsum Aug 17 '22 at 18:01

1 Answers1

1

I would do all this in different approach, model-driven and per-item, to have more control on effects.

A possible approach, is to add items into source of truth one by one and add effects depending on this collection growing.

Here is a demo. Tested with Xcode 14 / iOS 16

demo

Main parts:

@State private var items = [Int]()   // storage

...

ScrollViewReader { sr in
    ScrollView(showsIndicators: false) {
      // ...
    }
}
.onAppear {
    items.append(1)   // initial item put
}

...

// iterating model ...
ForEach(items, id: \.self) { index in
    // content
    Text("\(index)").id(index).font(.system(size: 64))
    // ... it is appeared, so we can use transition
        .transition(index == items.last ? .opacity : .identity)
        .onAppear {
            // on last appeared scedule add next ...
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.82) {
                if index == items.last && index < 50 {
                    items.append(index + 1)
                }
                DispatchQueue.main.async {
                    // ... and animate scrolling to it after add
                    withAnimation {
                        sr.scrollTo(index + 1)
                    }
                }
            }
        }

Test code is here

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • I updated my code with an array of string that is not empty, can you update the answer? – jooh Aug 18 '22 at 16:18