Scroll to a specific position in SwiftUI with button click

In order to scroll to a specific position in swiftUI we have something that we can use which is ScrollViewReader. We can tell it where to scroll and it will automatically scroll to that position. It comes with a proxy that only needs an id for that specific position we want to scroll to.

If you want to make auto scroll you can check: Auto scroll to a specific position in SwiftUI

I will show you the scroll on click with and without animation.

So let’s see how we can use it.

Scrolling to a specific position in SwiftUI

 

         
           ScrollView{    
                 Button(action: {
                      //Move to bottom
                 }, label: {
                     
                     Text("Move to bottom").font(.headline)
                     
                 })
                 .frame(maxWidth: .infinity)
                 .frame(height: 60)
                 .background(Color.black)
                 .cornerRadius(8)
                 .foregroundColor(Color.white)
                 .shadow(radius: 20)
                 .padding(4)
                 
                 
                 ForEach(0..<20){ index in
                     
                     Text("hello world")
                         .font(.title2)
                         .foregroundColor(.purple)
                         .frame(maxWidth: .infinity)
                         .frame(height: 50)
                         .background(Color.white)
                         .cornerRadius(8)
                         .shadow(color: .gray, radius: 6)
                         .padding(5)
                         .id(index)
                     
                 }

                 Button(action: {
             //move to Top
     
                 }
                        , label: {
                     Text("Move to Top").font(.headline)   })
                 
                 .frame(maxWidth: .infinity)
                 .frame(height: 60)
                 .background(Color.black)
                 .cornerRadius(8)
                 .foregroundColor(Color.white)
                 .shadow(radius: 20)
                 .padding(5)
              
        
     }

So here we have taken a scroll view and added a button at the top and bottom of the scroll view. In between those buttons, there are 20 text views.

Auto scroll to a specific position in SwiftUI

 

Now we’ll add the ScrollViewReader in the ScrollView. It’s pretty simple all we have to do is wrap all the content in the ScrollViewReader reader.

struct ContentView: View {
    var body: some View {
        
       
            ScrollView{
                ScrollViewReader{ proxy in
                  
                    Button(action: {
                     //scroll to bottom 
   
                    }, label: {
                        
                        Text("Move to bottom").font(.headline)
                        
                    })
                    .frame(maxWidth: .infinity)
                    .frame(height: 60)
                    .background(Color.black)
                    .cornerRadius(8)
                    .foregroundColor(Color.white)
                    .shadow(radius: 20)
                    .padding(4)
                    
                    
                    ForEach(0..<20){ index in
                        
                        Text("hello world")
                            .font(.title2)
                            .foregroundColor(.purple)
                            .frame(maxWidth: .infinity)
                            .frame(height: 50)
                            .background(Color.white)
                            .cornerRadius(8)
                            .shadow(color: .gray, radius: 6)
                            .padding(5)
                            .id(index)
                        
                    }

                    Button(action: {
                    //scroll to top                       
                        
                    }
                           , label: {
                        Text("Move to Top").font(.headline)   
                    })
                    
                    .frame(maxWidth: .infinity)
                    .frame(height: 60)
                    .background(Color.black)
                    .cornerRadius(8)
                    .foregroundColor(Color.white)
                    .shadow(radius: 20)
                    .padding(5)
                 
                }
                
            
           
        }
        
    }
}

 

So now If I wanted to be scrolled down to the number 19, which is the bottom of our scroll view, or any number really, we just have to access this proxy that comes with the ScrollViewReader. Proxy is basically reading the size of the scroll view so it knows where each of these items is.

ScrollViewReader{ proxy in

 //your scroll view content will go here
}

Now to scroll we just need to call a function on this proxy. Which is a scrollTo function that takes the id and an anchor.

     proxy.scrollTo(19,anchor: nil)

 

  • Now we have two options one is to scroll to id and the other one is to scroll to id with an anchor point.
  • anchor: The alignment behavior of the scroll action, for example, Top, Bottom, center, etc. If we set the anchor point to the top the number 19 will appear at the top of the screen after auto-scrolling.

ID is going to be basically the index we want to scroll to. So for starters let’s put the number 19, which is the index ID of our bottom view, in the first button at the top of the scroll view and the number 0, which is the index ID of our top view, in the button that is at the bottom of the scroll view. and then set the anchor, an anchor is where we want to be on the screen like the center and as its optional so it can also be nil.

 

struct ContentView: View {
    var body: some View {
        
       
            ScrollView{
                ScrollViewReader{ proxy in
                  
                    Button(action: {
                        //scroll to bottom
                        proxy.scrollTo(19,anchor:.top)
                         
                    }, label: {
                        
                        Text("Move to bottom").font(.headline)
                        
                    })
                    .frame(maxWidth: .infinity)
                    .frame(height: 60)
                    .background(Color.black)
                    .cornerRadius(8)
                    .foregroundColor(Color.white)
                    .shadow(radius: 20)
                    .padding(4)
                    
                    
                    ForEach(0..<20){ index in
                        
                        Text("hello world")
                            .font(.title2)
                            .foregroundColor(.purple)
                            .frame(maxWidth: .infinity)
                            .frame(height: 50)
                            .background(Color.white)
                            .cornerRadius(8)
                            .shadow(color: .gray, radius: 6)
                            .padding(5)
                            .id(index)
                        
                    }

                    Button(action: {
                      //scroll to top
                        proxy.scrollTo(0,anchor: .center)
                        
                    }
                           , label: {
                        Text("Move to Top").font(.headline)   })
                    
                    .frame(maxWidth: .infinity)
                    .frame(height: 60)
                    .background(Color.black)
                    .cornerRadius(8)
                    .foregroundColor(Color.white)
                    .shadow(radius: 20)
                    .padding(5)
                 
                }
                
            
           
        }
        
    }
}

Don’t forget to give the ID to your text views. Without ID  the proxy doesn’t know where the number 19 is. We need to explicitly tell where each item is. So we do that by giving the item a .id  and the id will just be the index. Now the proxy knows that the id with the number 19 is the one with the index 19. now it will scroll us down to item number 19.

      Text("hello world")
       .id(index)

 

Auto scroll to a specific position in SwiftUI without animation

 

Scrolling with animation in SwiftUI

Currently, it’s just jumping not scrolling like it would naturally but we can easily make it scroll by adding some animation.

 Button(action: {

                        //scroll to bottom

                        withAnimation(.spring()){

                            proxy.scrollTo(19,anchor: nil)}           

                    }, label: {

                        Text("Move to bottom").font(.headline)

                    })

 

//
//  ContentView.swift
//  audioApp
//
//  Created by test on 4/23/23.
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        
       
            ScrollView{
                ScrollViewReader{ proxy in
                  
                    Button(action: {
                        //scroll to bottom

                        withAnimation(.spring()){
                            proxy.scrollTo(19,anchor: nil)}
                         
                    }, label: {
                        
                        Text("Move to bottom").font(.headline)
                        
                    })
                    .frame(maxWidth: .infinity)
                    .frame(height: 60)
                    .background(Color.black)
                    .cornerRadius(8)
                    .foregroundColor(Color.white)
                    .shadow(radius: 20)
                    .padding(4)
                    
                    
                    ForEach(0..<20){ index in
                        
                        Text("hello world")
                            .font(.title2)
                            .foregroundColor(.purple)
                            .frame(maxWidth: .infinity)
                            .frame(height: 50)
                            .background(Color.white)
                            .cornerRadius(8)
                            .shadow(color: .gray, radius: 6)
                            .padding(5)
                            .id(index)
                        
                    }

                    Button(action: {
                      //scroll to top
                        withAnimation(.spring()){
                            proxy.scrollTo(0,anchor: .center)
                        }
                        
                    }
                           , label: {
                        Text("Move to Top").font(.headline)   })
                    
                    .frame(maxWidth: .infinity)
                    .frame(height: 60)
                    .background(Color.black)
                    .cornerRadius(8)
                    .foregroundColor(Color.white)
                    .shadow(radius: 20)
                    .padding(5)
                 
                }
                
            
           
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

If we add a number that’s outside the range like 21 it won’t crash but It’s not going to scroll either because there is no item in the ScrollViewReader with the ID of 21. So the ScrollViewReader is smart and also safe.

Scrolling with animation in SwiftUI

Leave a Reply

Your email address will not be published. Required fields are marked *