A ScrollView bounce behavior configuration allows you to define whether a scrollable view bounces when reaching the end of its content. Whether it’s a horizontal or vertical scrolling list, you can configure both directions using view modifiers in SwiftUI.
There are common scenarios for us to build when it comes down to lists. You might want to disable bouncing completely or only enable it when the size of the inner content becomes larger than its parent list bounds. Let’s dive in!
How to enable ScrollView Bounce
SwiftUI enables ScrollView bounce by default when you generate a plain scrolling view:
ScrollView {
Text("Small Content")
}
However, you can explicitly enable bouncing using the scrollBounceBehavior(_:axes:)
modifier:
ScrollView {
Text("Small Content")
}.scrollBounceBehavior(.always)
The above code example creates a ScrollView that will bounce in any direction, no matter the size of its content. Note that the same modifier applies to a List, Table, or TextEditor SwiftUI view.
How to disable vertical ScrollView bounce
You might want to disable horizontal or vertical ScrollView bounce in all cases. Unfortunately, there’s currently no better way than to use the appearance API for disabling:
/// Not recommended as it disables bounces for all your app's ScrollViews.
UIScrollView.appearance().bounces = false
However, this will turn it off for all your ScrollViews, which is not recommended. It’s important to understand that bouncing has a purpose: it naturally tells your users they’ve reached the end of the view. It’s best practice only to disable it if the content is small enough not even to be scrollable. In other words, the ScrollView feels like a non-scrollable view to the user so that the user won’t expect a bouncing behavior.
Disabling ScrollView bounce based on the content size
I recommend configuring your ScrollView bouncing behavior based on the size of its contents. Doing so brings the best of both worlds and ensures a user experience without confusion.
In the following code example, I’ve created a view with a orange bounding box to illustrate the size of our content:
struct ContentView: View {
var body: some View {
ScrollView {
Group {
Text("Small")
Text("Content")
}.background(Color.orange)
}
.scrollBounceBehavior(.always)
.frame(maxHeight: .infinity)
}
}
When running this view in the Simulator, you’ll notice that it doesn’t make sense for this view to be scrollable:
In this case, the size of the ScrollView’s content is small enough not to require scrolling. Therefore, we can configure the scroll bounce behavior to be based on the size:
ScrollView {
Group {
Text("Small")
Text("Content")
}.background(Color.orange)
}
// Only enable scrolling when the content is large enough.
.scrollBounceBehavior(.basedOnSize)
.frame(maxHeight: .infinity)
You’ve now disabled the ScrollView bounce based on the content size, which will enable it when the user is required to scroll to see the whole inner content.
Understanding bounce behavior’s environment configuration
The scroll bounce behavior modifier uses the Environment for its configuration. This means that an outer view can configure the bounce behavior of an inner view:
VStack {
ScrollView {
Group {
Text("Small")
Text("Content")
}.background(Color.orange)
}
}
/// Even though we configure the bounce behavior on the outer VStack,
/// the inner ScrollView will still respond to this setting and only enable
/// scrolling when the size of its content requires so.
.scrollBounceBehavior(.basedOnSize)
.frame(maxHeight: .infinity)
Even though we’ve configured the scroll behavior using the outer VStack
component, we still affect the inner ScrollView behavior.
Configuring ScrollView bounce for a specific axis
Finally, you can configure the ScrollView bounce behavior for a specific axis. In case you only want to affect horizontal scrolling views, you can use the following code:
.scrollBounceBehavior(.basedOnSize, axes: .horizontal)
The axes argument allows you to pass either vertical
or horizontal
.
Conclusion
ScrollView bounce behavior in SwiftUI can be configured to have the best outcome for the user’s expectation. Ideally, you would enable bouncing based on the size of the inner contents, as bouncing helps the user understand they reached the end of your view.
If you want to improve your SwiftUI knowledge, even more, check out the SwiftUI category page. Feel free to contact me or tweet me on Twitter if you have any additional tips or feedback.
Thanks!