1

In a giant ScrollView, I want to place Circles, and scroll to them so that, when scrolled, they end up in the middle of the screen, one after another.

I can position the Circles either by using .position, .offset or .padding. I have positioned them (300,300) away from one-another, and so that none of them are on screen when the view is loaded.

When I scroll to the ones positioned with .position or .offset, the ScrollView scrolls to the top left. .offset scrolls with an inset, .position all the way. When I scroll to the one positioned with .padding, it is not centred.

What am I doing wrong here? Why will none of my three attempts scroll so that the circle in question is placed in the middle of the ScrollView?

struct CanvasTester: View {
    
    @State var i = 0
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            ScrollViewReader { scrollView in
                ScrollView([.horizontal, .vertical]) {
                    ZStack(alignment: .topLeading) {
                        Spacer()
                            .frame(width: 4096, height: 4096)
                            .background(Color.yellow)
                            .task {
                                @Sendable func f() {
                                    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                                        withAnimation {
                                            scrollView.scrollTo("circle\(i+1)", anchor: .center)
                                            self.i = (self.i + 1) % 3
                                        }
                                        f()
                                    }
                                }
                                f()
                            }
                        
                        Circle()
                            .stroke(Color.blue, lineWidth: 4)
                            .frame(width: 44, height: 44)
                            .offset(x: 1500, y: 1500)
                            .id("circle1")

                        Circle()
                            .stroke(Color.green, lineWidth: 4)
                            .frame(width: 44, height: 44)
                            .position(x: 1800, y: 1800)
                            .id("circle2")

                        Circle()
                            .stroke(Color.red, lineWidth: 4)
                            .frame(width: 44, height: 44)
                            .padding([.top, .leading], 2100)
                            .id("circle3")
                    }
                }
            }

            Text("#\(i+1)")

        }
    }
}

Quick run-through the code: I have a ScrollReader encapsulating a ScrollView that scrolls both directions and is 4096x4096. It has a yellow background that on draw launches a function that every second scrolls to the view with either ID "circle1", "circle2" or "circle3". Then follow the three circles with those labels, and finally a label I the top left corner to indicate what color number the ID has.

niklassaers
  • 8,480
  • 20
  • 99
  • 146
  • Don't use `offset` it is not for that purpose as you supposed: the view itself remains at {0,0}. – Asperi Feb 09 '22 at 16:18

0 Answers0