I am using ScrollView, and is that possible to scroll the view to the top when I do any actions, such as click button and etc?
5 Answers
I think that currently the best way to do it is using the View´s id function
- Declare a state var with a unique id
@State private var scrollViewID = UUID()
and then add the id function to the ScrollView
ScrollView(.horizontal, showsIndicators: true) { // ... }.id(self.scrollViewID)
Whenever you change that id - for example in a button event - the scrollview is rebuilt from scratch - which is like scrolling to the top
- 107
- 1
- 3
-
2When I tried this I saw the view reevaluated but the scroll position stayed the same. – t9mike Jan 11 '21 at 01:48
In just published ScrollViewProxy.
A proxy value allowing the scrollable views within a view hierarchy to be scrolled programmatically. – https://developer.apple.com/documentation/swiftui/scrollviewproxy
Xcode 12.0 beta (12A6159)
- 2,534
- 1
- 15
- 18
There is a workaround that can accomplish ScrollToTop() effect by hiding everything before showing new content.
@State var hideEverything = false
var body: some View {
ScrollView {
if hideEverything {
EmptyView()
} else {
// your content view
}
}
}
func ScrollToTop() {
self.hideEverything = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01)
{
self.data = ... // update data source
self.hideEverything = false
}
}
- 112
- 3
From iOS 14, maybe before.
struct Example: View {
private static let topId = "topIdHere"
/*
Use only for toggling, binding for external access or @State for internal access
*/
@Binding var shouldScrollToTop: Bool = false
var body: some View {
ScrollViewReader { reader in // read scroll position and scroll to
ScrollView {
VStack {
TopView() // << first view on top
.id(Self.topId) // << assigned id (use for scroll)
}
.onChange(shouldScrollToTop) { _ in
withAnimation { // add animation for scroll to top
reader.scrollTo(Self.topId, anchor: .top) // scroll
}
}
}
}
}
}
Something like that ?)
- 1,806
- 1
- 15
- 18
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
- 2,526
- 2
- 12
- 32