Swipe TabView mapped to scrollable HStack with images

Hi! I'm trying to create a view where the user should be able to select images from a recorded video as in the attached example image.

There should be a scrollable HStack, showing every 20th frame from the recorded video, with a vertical line (horizontally positioned at the middle of the screen) marking the current frame. The current frame should be shown as an enlarged image above the thumbnail images. The user should be able to swipe the enlarged image to go between frames, i.e. scroll one frame position back or forth (and also be able to change frame by dragging/scrolling the HStack, but that will be a later problem).

I have managed to generate frames from a recorded video and set up a TabView to present the current frame (enlarged image) with swiping functionality, and a ScrollView below to present the thumbnails. But I can't figure out how to get the scrollTo-funcitonality to work. Right know the scrolling positions are off (my invisible scroll to-elements do not line up correctly with the thumbnail images. I have attached my messy code of the scrollable HStack if that is of any help.

Thankful for any tips!

`struct ViewOffsetKey: PreferenceKey {

    typealias Value = CGFloat

    static var defaultValue = CGFloat.zero

    static func reduce(value: inout Value, nextValue: () -> Value) {

        value += nextValue()

    }

}

struct ViewMinXKey: PreferenceKey {

    typealias Value = CGFloat

    static var defaultValue = CGFloat.zero

    static func reduce(value: inout Value, nextValue: () -> Value) {

        value += nextValue()

    }

}

struct ViewMaxXKey: PreferenceKey {

    typealias Value = CGFloat

    static var defaultValue = CGFloat.zero

    static func reduce(value: inout Value, nextValue: () -> Value) {

        value += nextValue()

    }

}

struct StackedPhotosView: View {

    @EnvironmentObject var videoManager: VideoManager

    @State var minX: CGFloat = 0.0

    @State var maxX: CGFloat = 0.0

    

    var body: some View {

        GeometryReader { geometry in

            ScrollViewReader { reader in

                ScrollView(.horizontal) {

                            HStack(spacing: 0) {

                                

                                // Rectangle to create an offset so that the thumbnail images start at the middle of the screen

                                Rectangle().frame(width:geometry.size.width/2, height: 70).foregroundColor(Color.clear)

                                ZStack {

                                    HStack(spacing: 0) {

                                        

                                        // Show every 20th image

                                        ForEach(Array(videoManager.frames.enumerated()), id: .1.id) { (index, item) in

                                            

                                            if index % 20 == 0 {

                                                Image(uiImage: item.image)

                                                    .resizable()

                                                    .border(.black, width: 1)

                                                    .frame(height: 70)

                                                    .aspectRatio(1.0, contentMode: .fit)

                                                    .rotationEffect(.degrees(90))

                                            }

                                        }

                                    }

                                    

                                    if maxX > 0 {

                                        // Create invisible "scroll to" elements with ids for every frame

                                        HStack(spacing:0) {

                                            ForEach(videoManager.frames.indices, id: .self) { i in

                                                Spacer()

                                                    .id(i)

                                                    .frame(width: Double((maxX-(geometry.size.width/2))/CGFloat(videoManager.frames.count)), height: 70)

                                                    .foregroundColor(.red)

                                                    .border(.black, width: 1)

                                                    .opacity(0.5)

                                            }

                                        }

                                    }

                                }

                                

                                // Rectangle extending the HStack and making all images being able to pass the vertical blue line

                                Rectangle().frame(width:geometry.size.width/2, height: 70).foregroundColor(Color.clear)

                            }

                            .background(GeometryReader  {

                                Color.clear.preference(key: ViewOffsetKey.self,

                                                       value: -$0.frame(in: .named("scroll")).origin.x) // Will be used later to change top image when drag-scrolling on the HStack

                                Color.clear.preference(key: ViewMinXKey.self,

                                                       value: $0.frame(in: .local).minX)

                                Color.clear.preference(key: ViewMaxXKey.self,

                                                       value: $0.frame(in: .local).maxX - geometry.size.width)

                            })

                }

                .onChange(of: videoManager.currentFrameNr, perform: { index in

                    withAnimation(.linear) {

                        reader.scrollTo(index, anchor: .leading)

                    }

                })

                .onPreferenceChange(ViewMinXKey.self) {

                    minX = CGFloat($0)

                }

                .onPreferenceChange(ViewMaxXKey.self) {

                    maxX = CGFloat($0)

                }

            }

                }

    } }`

Swipe TabView mapped to scrollable HStack with images
 
 
Q