Use TabView to implement inifinite scroll like the WeekView of Calendar app

Viewed 38

I am trying to implement a component with a "Horizontal Scroll View" of weekdays similar to the iOS Calendar App. When the user swipe left/right, the dates in scope will be updated to the previous/next week with animation just like the pagers.

enter image description here

I thought the feature is simple enough so I didn't intend to use any third-party framework. I tried TabView to dynamically append items to the beginning/end of the items array, but the animation seems buggy. The problem shows up when the code inserts a new element at the beginning of the array. I'm confused why everything looks good when the element is appended to the last.

Not sure whether it's the right direction I should dig into for this feature. Any suggestions?

struct ContentView: View {
    @State private var selection = "2"
    
    @State var items: [String] = ["0", "1", "2", "3", "4"]
    
    var body: some View {
        TabView(selection: $selection) {
            ForEach(items, id: \.self) { item in
                Text(item)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .tag(item)
            }
        }
        .tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
        .onChange(of: selection, perform: { value in
            if items.firstIndex(of: value) == items.count - 2, let last = items.last, let number = Int(last) {
                self.items.append("\(number + 1)")
            }
            if items.firstIndex(of: value) == 1, let first = items.first, let number = Int(first) {
                self.items.insert("\(number - 1)", at: 0)
            }
        })
//        .id(items.count) // <-- This will rerender the list so the animation will be interrupted when count is changed.
    }
}
0 Answers
Related