2

I can not understand why the timer does not work, and the text does not scroll automatically.

I tried to do so:

ForEach(0..<numberText)

But I got such an error:

Referencing initializer 'init(_:content:)' on 'ForEach' requires that 'some View' conform to 'TableRowContent'

Full code:

let numberText = ["text1","text2","text3","text4"]

struct TextNew: View {
    
    private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
    @State private var index = 0
    
    let textdata = TextData.getAllText()
    
    var body: some View {
        
        GeometryReader { proxy in
            
            TabView(selection: $index) {
                
                ForEach(numberText, id: \.self) { num in
                    
                    Text("\(num)")
                        .font(.system(size: 10))
                        .foregroundColor(.white)
                        .tag(num)
                        .padding(.bottom, 50)
                    
                }
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .frame(height: 80)
            .onReceive(timer, perform: { _ in
                withAnimation {
                    index = index < numberText.count ? index + 1 : 0
                    
                }
            })
            
        }
    }
}

Thanks for any help, I'm new

  • Your `Timer` runs fine with this code. You can test it by writing `print("Timer fired")` within your `onReceive` closure. What's unclear is what you expect to happen with `index = index < numberText.count ? index + 1 : 0`, since `index` isn't actually *used* anywhere in the UI. – jnpdx Apr 21 '22 at 20:20
  • @jnpdx Then why doesn't the text change automatically? –  Apr 21 '22 at 20:22
  • @jnpdx I expect the text to scroll automatically after a given timer, but this does not happen –  Apr 21 '22 at 20:31
  • 1
    Looks like @burnsi beat me to a possible solution, but to elaborate on why their answer works, your `tag` type has to match the `selection` parameter type. Right now, you're trying to compare a `String` to an `Int`. Also worth mentioning that `.self` is potentially dangerous as an `id` unless the data will never change (which, to be fair, in your example, is true). – jnpdx Apr 21 '22 at 20:41
  • @jnpdx thank you for the explanation) –  Apr 21 '22 at 21:13

1 Answers1

4

Try this:

struct TextNew: View {
    
    private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
    @State private var index = 1
    @State private var selectedNum: String = ""
    
    var body: some View {
        
        GeometryReader { proxy in
            
            TabView(selection: $selectedNum) {
                
                ForEach(numberText, id: \.self) { num in
                    Text("\(num)")
                        .font(.system(size: 10))
                        .foregroundColor(.white)
                        .padding(.bottom, 50)
                }
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            
            .onReceive(timer, perform: { _ in
                withAnimation {
                    index = index < numberText.count ? index + 1 : 1
                    selectedNum = numberText[index - 1]
                }
            })
            
        }
    }
}

Explanation:

The reason for this not working is the type mismatch between your .tag and the $index in your TabView declaration. These have to match. By the way you do not need the .tag here as you are setting it to .self in your ForEach loop.

burnsi
  • 6,194
  • 13
  • 17
  • 27