With the release of SwiftUI 2 and iOS 14, we now have access to a new view called ScrollViewReader that exposes an object called ScrollViewProxy. What this allows us to do is programmatically control where a user is scrolled to in a view — and send users to a specific spot in your long view.
To test this out, I wanted to create a custom scroll control using a slider to determine where the user was in the ScrollView. The user would be able to drag the slider, which controls where the user is.
Fortunately, the new views in SwiftUI 2 allow us to do this.
The scroll view controlled by a slider
To get this to work, we first need to create some state that can be our source of truth for the current scroll position. Both scroll position and the slider value use CGFloat.
@State var scrollPosition: CGFloat = 0.0
We will use this to keep the slider and the scroll position in sync.
Next, let’s add the views we need to replicate the example.
VStack {
Slider(value: $scrollPosition)
ScrollView {
ScrollViewReader { scrollProxy in
Text(text)
.id("text")
.padding()
.onChange(of: scrollPosition) { newScrollPosition in
scrollProxy.scrollTo("text", anchor: UnitPoint(x: 0, y: newScrollPosition))
}
}
}
}
Let’s unpack this:
scrollPosition
binding to our Slider value.scrollTo
method. More on that in a second…scrollTo
.scrollPosition
, as defined on line 2 and is set by our slider, which then gives us access to the new value within the callback. I’ve defined this as newScrollPosition
.scrollTo
method. scrollTo
takes two arguments, the first one is the id of the item we want to scroll to. In this case, I’m passing it the id “text”, which is the same id we gave to our text view on line 6. If you have multiple items within your scroll view (for example a list), you can scroll to a particular item using this argument. The second argument is optional, and allows you to scroll to a particular position within the item itself.UnitPoint()
, which has two values, x
and y
. Both of these values take a CGFloat
, with a number between 0.0 and 1.0 determining how far along we want to scroll to. In this case, we’re going to leave x
as 0 because we don’t want to scroll horizontally. We’re then going to set y
to the value of newScrollPosition
.So, every time scrollPosition
is updated, the onChange
callback is called where newScrollPosition
contains the new value. scrollTo
is then called with this new value, causing the text view scroll position to move. The newScrollPosition
will be a value of between 0.0 and 1.0 from the slider, and UnitPoint()
also describes where the view is scrolled to relative to the length of the view between 0.0 and 1.0, so they match up perfectly.
#ios #scrollview #swift #swiftui #ios-app-development