Scrollable Containers in Jetpack Compose
In this article, we are going to explore scrollable containers in Compose.
By the end of it, you'll either learn something new, get more clarity on the available APIs, or at least refresh what you already know ๐
Let's dive in
In Compose, we can make any container scrollable by using the rememberScrollState()
function.
First, we may instantiate the ScrollState
val scrollState = rememberScrollState()
Then, we can pass it down to any composable through its Modifier
. There are a few modifier functions available at our disposal:
Using scrollable
One way is to use the scrollable
modifier function, where we need to pass down the state
, as well as orientation
(so that Compose knows in which direction the scroll will be scrolling).
Box(
modifier = Modifier
.scrollable(state = scrollState, orientation = Orientation.Vertical)
)
Those 2 are the only mandatory arguments that we have to pass when using the scrollable
modifier function. However, there are a few optional arguments that we can provide too:
modifier = Modifier
.scrollable(
state = scrollState,
orientation = Orientation.Vertical,
enabled = true,
reverseDirection = false,
flingBehavior = null,
interactionSource = null
)
Let's look into them 1 by 1.
enabled
(defaulting to true
) - defines whether the scroll is enabled for the user. It could be useful in situations where we want to prevent the user from scrolling.
Such cases might be: requiring the user to enter some text or tick a check box to enable the scroll, or when we only need to do the scroll programmatically.
reverseDirection
(defaulting to false
) - defines whether the direction of the scroll will go in the opposite side of the scrolling direction.
flingBehavior
- allows us to define different scrolling behavior than the default one. An example would be a situation where we need to snap the scrollable items to a specific position.
Think of scrolling photos (like a gallery app) or videos (like Instagram/TikTok reels) that we want to snap edge to edge, once the item passes a certain threshold.
interactionSource
- allows us to hook into the stream of drag events that are coming while the user is dragging. Haven't used this parameter so far, so I am not certain about all the possibilities it provides.
Using horizontalScroll()
/ verticalScroll()
Another way to pass the state down to the modifier is to use one of the convenience functions horizontalScroll()
or verticalScroll()
These functions encapsulate the orientation
argument inside, respectively.
Box(modifier = Modifier.horizontalScroll(state = scrollState))
//
Box(modifier = Modifier.verticalScroll(state = scrollState))
Other than orientation
and interactionSource
, these functions also expose the rest of the arguments we've seen in the scrollable
function.
Usability
This approach is useful when we need to make a container that contains a few items scrollable.
From my experience, most of the time you'll end up using the horizontalScroll
or verticalScroll
convenience functions, and pass to them the scrollState
.
That would cover most of the cases where we might need a scrollable container.
Optimization
However, this approach is not optimal and it is less than ideal for situations where we have many (or a lot) of items that we need to scroll.
When we need to display a list of 10s or 100s of items, a more optimal approach would be to use a Lazy container, such as LazyColumn
, LazyRow
, LazyGrid
etc.
These containers provide recycling optimization similar to the old good RecycleView
We will explore them much more in-depth, what are the possibilities, and the ways we can use them in the next article: LazyX in Jetpack Compose
Happy Composing!
P.S. Check out the Android Devs Skool Community and join us.