swiftswiftui

How to scroll to the top of a ScrollView in SwiftUI


I am using a ScrollView; is that possible to scroll the view to the top when I do any actions, such as clicking a button, etc.?


Solution

  • Of course from iOS 14.0 and later you should use ScrollViewProxy, definitely it has been developed for this reason.

    But if you check when the question has been asked, you'll define the answer was for iOS 13.0, the SwiftUI 1.0 and at that point of time you had to reinvent the bicycle somehow:

    Using this solution (previously simplified) I made example of moving ScrollView.content.offset strict to the top when button pressed:

    struct ScrollToTheTop: View {
        
        @State private var verticalOffset: CGFloat = 0.0
        @State private var gestureOffset: CGFloat = 0.0
        @State private var itemCount: Int = 200
        
        var body: some View {
            
            NavigationView {
                VStack {
                    
                    ScrollView(.vertical, showsIndicators: false) {
                        
                        VStack {
                            
                            ForEach(1...itemCount, id: \.self) { item in
                                Text("--- \(item) ---") // height 17.5
                            }
                            
                        }
                        
                    }
                    .content.offset(y: (self.verticalOffset + self.gestureOffset)
                        // all the content divided by 2 for zero position of scroll view
                        + CGFloat(17.5 * Double(self.itemCount/2)))
                        .gesture(DragGesture().onChanged( { value in
                            self.gestureOffset = value.translation.height
                        }).onEnded( { value in
                            withAnimation {
                                // here should calculate end position with value.predictedEndLocation.y
                                self.verticalOffset += value.translation.height
                                self.gestureOffset = 0.0
                            }
                        }))
                    
                    
                }.navigationBarItems(trailing: Button("To top!") {
                    withAnimation {
                        self.verticalOffset = 0.0
                    }
                })
            }
            
        }
        
    }
    

    if this example fits, you have to refine DragGesture