ScrollViewReader came into picture with the release of iOS 14.
ScrollViewReader is a view that provides programmatic scrolling. It creates a ScrollViewProxy to scroll child views. It gives us access to a function called ScrollTo which let’s us make a view visible by scrolling to it. It can be better understood with an example so let’s put one together.
For this example, we will create two id values of type Namespace. These ids will help us scroll to the top and bottom of scrollView with the help of scrollTo function defined in ScrollViewProxy.
Namespace is a dynamic property type that allows access to a namespace defined by the persistent identity of the object containing the property (e.g. a view).
struct DevTechieScrollViewReader: View {
@Namespace var topID
@Namespace var bottomID
var body: some View {
NavigationStack {
ScrollViewReader { scrollViewProxy in
ScrollView {
Button("Scroll to the bottom") {
withAnimation {
scrollViewProxy.scrollTo(bottomID)
}
}
.id(topID)
VStack {
ForEach(0..<30) { idx in
Image(systemName: "\(idx).circle.fill")
.font(.largeTitle)
.foregroundColor(.orange)
}
}
Button("Scroll to the top") {
withAnimation {
scrollViewProxy.scrollTo(topID)
}
}
.id(bottomID)
}
}
}
}
}
We don’t have to use namespace as an id. We can use simple integer or any hashable type as well for this purpose. Let’s update our example to use integer index as the id to identify each row.
struct DevTechieScrollViewReader: View {
var body: some View {
NavigationStack {
ScrollViewReader { scrollViewProxy in
ScrollView {
Button("Scroll to the bottom") {
withAnimation {
scrollViewProxy.scrollTo(1)
}
}
.id(0)
VStack {
ForEach(0..<30) { idx in
Image(systemName: "\(idx).circle.fill")
.font(.largeTitle)
.foregroundColor(.orange)
}
}
Button("Scroll to the top") {
withAnimation {
scrollViewProxy.scrollTo(0)
}
}
.id(1)
}
}
}
}
}
ScrollViewProxy
A ScrollViewProxy provides scrollTo function which scans all contained scroll views, looking for the first view with the specified id and then scrolls to that view.
scrollTo function takes two parameters:
id: is the id of the view that will be scrolled into the view. The id can be any Hashable type.
anchor: anchor is used for alignment, if its nil(default value) then the view will be scrolled the minimum amount to make the entire view visible. If anchor is defined(non-nil), it will determine the point in the view and scroll view will be aligned to that point. Here are all the possible values for anchor:
Let’s update our view to have three points we can scroll to.
struct DevTechieScrollViewReader: View {
var body: some View {
NavigationStack {
ScrollViewReader { scrollViewProxy in
ScrollView {
Button("Scroll to the middle") {
withAnimation {
scrollViewProxy.scrollTo("center", anchor: .center)
}
}
.id("top")
VStack {
ForEach(0..<50) { idx in
Image(systemName: "\(idx).circle.fill")
.font(.largeTitle)
.foregroundColor(.orange)
if idx == 25 {
Button("Scroll to the bottom") {
withAnimation {
scrollViewProxy.scrollTo("bottom", anchor: .bottom)
}
}
.id("center")
}
}
}
Button("Scroll to the top") {
withAnimation {
scrollViewProxy.scrollTo("top", anchor: .top)
}
}
.id("bottom")
}
}
}
}
}
With that we have reached the end of this article. Thank you once again for reading. Don’t forget to follow 😍. Also subscribe our newsletter at https://www.devtechie.com