0

This answer shows how to link 3 ScrollViews (a horizontal ScrollView for column headers, a vertical ScrollView for row headers, and a horizontal/vertical ScrollView for cells) and how to scroll the cells ScrollView to topLeading in onAppear. However on ios 16.4 where when the screen first appears the rowsHeader scrollview is not scrolled to the top and the colsHeader scrollview is not scrolled to the left. When the table scrollview is first scrolled manually the rowsHeader and colsHeaders scrollviews jump to the correct offset. Does anyone know how to fix this? Thank you

struct ContentView: View {
    
    let columns = 20
    let rows = 30
    
    @State private var offset = CGPoint.zero
    
    var body: some View {
        
        HStack(alignment: .top, spacing: 0) {
            
            VStack(alignment: .leading, spacing: 0) {
                // empty corner
                Color.clear.frame(width: 70, height: 50)
                ScrollView([.vertical]) {
                    rowsHeader
                        .offset(y: offset.y)
                }
                .disabled(true)
            }
            VStack(alignment: .leading, spacing: 0) {
                ScrollView([.horizontal]) {
                    colsHeader
                        .offset(x: offset.x)
                }
                .disabled(true)
                
                table
                    .coordinateSpace(name: "scroll")
            }
        }
        .padding()
    }
    
    var colsHeader: some View {
        HStack(alignment: .top, spacing: 0) {
            ForEach(0..<columns) { col in
                Text("COL \(col)")
                    .foregroundColor(.secondary)
                    .font(.caption)
                    .frame(width: 70, height: 50)
                    .border(Color.blue)
            }
        }
    }
    
    var rowsHeader: some View {
        VStack(alignment: .leading, spacing: 0) {
            ForEach(0..<rows) { row in
                Text("ROW \(row)")
                    .foregroundColor(.secondary)
                    .font(.caption)
                    .frame(width: 70, height: 50)
                    .border(Color.blue)
            }
        }
    }
    
    var table: some View {
        ScrollViewReader { cellProxy in
            ScrollView([.vertical, .horizontal]) {
                VStack(alignment: .leading, spacing: 0) {
                    ForEach(0..<rows) { row in
                        HStack(alignment: .top, spacing: 0) {
                            ForEach(0..<columns) { col in
                                // Cell
                                Text("(\(row), \(col))")
                                    .frame(width: 70, height: 50)
                                    .border(Color.blue)
                                    .id("\(row)_\(col)")
                            }
                        }
                    }
                }
                .background( GeometryReader { geo in
                    Color.clear
                        .preference(key: ViewOffsetKey.self, value: geo.frame(in: .named("scroll")).origin)
                })
                .onPreferenceChange(ViewOffsetKey.self) { value in
                    print("offset >> \(value)")
                    offset = value
                }
                
                // Use the following to scroll to the first cell (top leading corner of the table) when opened
                
                .onAppear {
                    cellProxy.scrollTo("0_0")
                }
            }
        }
    }
}


struct ViewOffsetKey: PreferenceKey {
    typealias Value = CGPoint
    static var defaultValue = CGPoint.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value.x += nextValue().x
        value.y += nextValue().y
    }
}
John Cashew
  • 1,078
  • 2
  • 12
  • 28

0 Answers0