肘子的 Swift 记事本

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.

I'm really looking forward to hearing your thoughts! Please Leave Your Comments Below to share your views and insights.

Fatbobman(东坡肘子)

I'm passionate about life and sharing knowledge. My blog focuses on Swift, SwiftUI, Core Data, and Swift Data. Follow my social media for the latest updates.

You can support me in the following ways