HowTo —— Using ScrollViewReader to Scroll to Position in SwiftUI 2.0

Published on

Get weekly handpicked updates on Swift and SwiftUI!

With SwiftUI 2.0, scroll positioning has become much easier to adapt to most application scenarios. The implementation method is completely different from various folk solutions in the past, and it is not done by setting specific offsets for positioning, but by using IDs to mark positions.

Basic Usage —— Implementing Horizontal Scroll from Right to Left

Swift
struct ScrollReaderTest: View {
    var body: some View {
        ScrollView(.horizontal) {
            // Similar to the usage of GeometryReader, set the scroll positioning area
            ScrollViewReader{ proxy in
                Rectangle()
                    .fill(LinearGradient(
                      gradient: Gradient(colors: [.blue,.red]),
                      startPoint: .leading,
                      endPoint: .trailing))
                    .frame(width: 1000, height: 300, alignment: .center)
                    .id("rec") // Set ID for the view in ScrollView that needs to be positioned
                    .onAppear {
                        // Scroll to the specified ID position, aligning according to the anchor setting
                        proxy.scrollTo("rec",anchor:.trailing)
                  }
            }
        }
    }
}

Scroll to Specific Position Using Buttons

Swift
import SwiftUI

struct ScrollReadeTest: View {
    private var list = ScrollItem.items(300)
    @State private var position:Int = 0
    var body: some View {
      NavigationView{
        ScrollView{
            ScrollViewReader{ proxy in
                LazyVStack{
                    ForEach(list,id:\.id){ item in
                        Text(item.title).id(item.id)
                    }
                }
                .onChange(of: position) { positon in
                    switch position{
                    case 1: 
                        let id = list.first!.id
                        withAnimation(Animation.easeInOut){
                            proxy.scrollTo(id,anchor:.top)
                        }
                    case 2:
                        
                        let id = list[Int(list.count / 2)].id
                        withAnimation(Animation.easeInOut){
                            proxy.scrollTo(id,anchor:.center)
                        }
                    case 3:
                        let id = list.last!.id
                        withAnimation(Animation.easeInOut){
                            proxy.scrollTo(id,anchor:.bottom)
                        }
                    default:
                        break
                    }
                }
            }
        }
        .navigationTitle("Scroll Positioning")
        
        .toolbar {
            ToolbarItem(placement:.automatic) {
                HStack{
                    Button("Top"){
                        position = 1
                    }
                    Button("Middle"){
                        position = 2
                    }
                    Button("End"){
                        position = 3
                    }
                }
            }
         }
      }
   }
}

struct ScrollItem:Identifiable{
    var id = UUID()
    var title:String
    
    static func items(_ count:Int) -> [ScrollItem]{
        var result:[ScrollItem] = []
        for i in 0..<count{
            result.append(ScrollItem(title:String("index:\(i) title:\(Int.random(in: 1000...5000))")))
        }
        return result
    }
}

Drawback

There is no simple way to record the current scroll position.

Explore weekly Swift highlights with developers worldwide

Buy me a if you found this article helpful