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.

1
  • Don't use offset it is not for that purpose as you supposed: the view itself remains at {0,0}. Commented Feb 9, 2022 at 16:18

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.