Search code examples
swiftxcodeswiftuiscrollviewtabbar

ScrollView Should Start from Specific Item in SwiftUI


I have an array of years and a selected year. What I want is whenever my View loads, it should move automatically to the selected year.

Here is my code:

struct Testing: View {
    let years = ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025", "2026"]
    @State var selectedYear = "2023"
    @Namespace private var animation
    
    var body: some View {
        
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 20) {
                
                ForEach(years.indices, id: \.self) { index in
                    
                    Button {
                        withAnimation(.linear(duration: 0.5)) {
                            selectedYear = years[index]
                        }
                    } label: {
                        VStack {
                            Text("\(years[index])")
                                .foregroundColor(.white)
                                .fontWeight(.semibold)
                                .padding(.horizontal, 15)
                            
                            if selectedYear == years[index] {
                                Capsule()
                                    .fill(.white)
                                    .frame(height: 5)
                                    .padding(.horizontal, -5)
                            }
                        }
                    }
                }
            }.padding().background {
                Rectangle()
                    .fill(Color.purple)
            }
        }
    }
}

This is returning

return image

Whenever the View loads it should show the selectedYear in the middle. How can I achieve this?


Solution

  • You can use ScrollViewReader container view which gives a mechanism to read a scroll view's content offset and scroll to a particular piece of material therein with scrollTo method. Here is the Updated code:

    struct Testing: View {
        let years = ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025", "2026"]
        @State var selectedYear = "2023"
        @Namespace private var animation
        
        var body: some View {
            
            ScrollView(.horizontal, showsIndicators: false) {
                ScrollViewReader { scrollView in // --> Here
                    HStack(spacing: 20) {
                        
                        ForEach(years.indices, id: \.self) { index in
                            
                            Button {
                                withAnimation(.linear(duration: 0.5)) {
                                    selectedYear = years[index]
                                }
                            } label: {
                                VStack {
                                    Text("\(years[index])")
                                        .foregroundColor(.white)
                                        .fontWeight(.semibold)
                                        .padding(.horizontal, 15)
                                    
                                    if selectedYear == years[index] {
                                        Capsule()
                                            .fill(.white)
                                            .frame(height: 5)
                                            .padding(.horizontal, -5)
                                    }
                                }
                                .id(years[index]) // ---> Here
                            }
                        }
                    }
                    .padding().background {
                        Rectangle()
                            .fill(Color.purple)
                    }
                    .onAppear {
                        scrollView.scrollTo(selectedYear, anchor: .center) // ---> Here
                    }
                }
            }
        }
    }