SwiftUIで、一行一列を固定したスプシの動作を再現したい時

![画面収録_2023-05-25_13_26_55_AdobeExpress-3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/b218f7bc-5518-b80b-2ea9-48c6a27f46bd.gif)


参考:

https://stackoverflow.com/questions/66591671/how-to-create-synced-scrollviews-in-swiftui

```swift
import SwiftUI

struct SyncedScrollViews<Content:View,VSyncedContent:View,HSyncedContent:View>: View {
    
    let content:Content
    let verticallySyncedContent:VSyncedContent
    let horizontallySyncedContent:HSyncedContent
    
    init(@ViewBuilder content: () -> Content, @ViewBuilder vSyncedContent: () -> VSyncedContent, @ViewBuilder hSyncedContent: () -> HSyncedContent) {
        self.content = content()
        self.verticallySyncedContent = vSyncedContent()
        self.horizontallySyncedContent = hSyncedContent()
    }
    
    @State private var offset = CGPoint(x: 0, y: 0)
    
    var body: some View {
        VStack(alignment: .leading,spacing: 0){
            Spacer()
            // Synchronised with main ScrollView
            ScrollView(.horizontal) {
                HStack {
                    horizontallySyncedContent
                }
                .offset(x: -offset.x)
            }
            .disabled(true)
            
            HStack(alignment: .top,spacing: 0) {
                // Synchronised with main ScrollView 
                ScrollView {
                    VStack {
                        verticallySyncedContent
                    }
                    .offset(y: -offset.y)
                }
                .disabled(true)
                
                // MainScrollView
                ScrollView([.vertical, .horizontal]) {
                    VStack {
                        content
                    }
                    .background( GeometryReader {
                        Color.clear.preference(key: ViewOffsetKey.self,
                                               value: CGPoint(x:-$0.frame(in: .named("scroll")).origin.x,y:-$0.frame(in: .named("scroll")).origin.y) )
                    })
                    .onPreferenceChange(ViewOffsetKey.self) { value in
                        print("offset >> \(value)")
                        offset = value
                        
                    }
                }
                .coordinateSpace(name: "scroll")
                
                
            }
        }
    }
}

struct ViewOffsetKey: PreferenceKey {
    static var defaultValue = CGPoint.zero
    
    typealias Value = CGPoint
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value.x += nextValue().x
        value.y += nextValue().y
    }
}



struct SyncedScrollViews_Previews: PreviewProvider {
    static var previews: some View {
        SyncedScrollViews{
            HStack{
                ForEach(1..<100) { column in
                    VStack{
                        ForEach(1..<100) { row in
                            Text("R:\(row)\nC:\(column)")
                                .frame(width: 80, height: 80)
                        }.background(.green)
                    }
                }
            }
        }vSyncedContent:{
            ForEach(1..<100) { row in
                Text("R:\(row)\nC:\(0)")
                    .frame(width: 80, height: 80)
            }.background(.pink)
                .padding(.trailing,8)
            
        }hSyncedContent:{
            ForEach(0..<100) { column in
                Text("R:\(0)\nC:\(column)")
                    .frame(width: 80, height: 80)
            }.background(.yellow)
                .padding(.bottom,8)
        }
        }
}


```



より抽象化できる部分があるなど、改善点など教えていただけると嬉しいです。