Instruction
The simplest way to build a scrolling list in XML is by using a ScrollView. ScrollView is an excellent candidate for building a scrolling UI when your list has fixed, finite and predictable items.
For those instances when your Compose UI calls for a simple list, with a fixed small set of items, the scroll modifiers in Compose are your go-to. They provide a convenient and efficient way to build a horizontal or vertical scrolling list.
Making Your Existing Row & Column Layouts Scrollable
By this point, you are already familiar with working with Row and Column composables. Depending on their direction, these layouts emit their items in the horizontal or vertical direction.
@Composable
fun Messages(messages: List<Message>) {
Column {
messages.forEach { message ->
MessageCard(message)
}
}
}
The example above shows that the resulting UI will be a vertical list of MessageCard components.
Row and Column are layout wrappers that we use to arrange the UI, but, they are not scrollable by default. If your use case requires your Row or Column to be scrollable, you need to specify that explicitly using modifiers.
Scroll Modifiers
The horizontalScroll and verticalScroll modifiers are a simple way to allow users the ability to scroll through your UI’s contents.
@Composable
fun Messages(messages: List<Message>) {
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
messages.forEach { message ->
MessageCard(message)
}
}
}
In the example above, to make the Column of message objects scrollable, you used the verticalScroll modifier and passed in rememberScrollState(). This creates a scroll state based on the scroll orientation and persists the scroll position so it isn’t lost after recomposition.
Its counterpart, horizontalScroll applies to Row layouts and lets users scroll horizontally.
@Composable
fun Photos(photos: List<Photo>) {
Row(modifier = Modifier.horizontalScroll(rememberScrollState())) {
photos.forEach { photo ->
PhotoItem(photo)
}
}
}
When this change is deployed on the device, the Column will render all the items and for items that go outside the screen bounds, you’ll be able to scroll to see them.
Exploring the Scroll Modifier(s)
Before going any further, it’ll be helpful to learn how the scroll modifiers work.
fun Modifier.verticalScroll(
state: ScrollState,
enabled: Boolean = true,
flingBehavior: FlingBehavior? = null,
reverseScrolling: Boolean = false
)
Here’s what the different parameters do
-
scrollStateis the current state of the scroll. Scroll state determines the offset from the top and can also be used to start or stop smooth scrolling and fling animations. -
enabledenables or disables scrolling. If disabled, you can still programmatically scroll to a specific position using thestateproperty scrolling via gestures will not work. -
flingBehavioris used to perform a fling animation with a given velocity. -
reverseScrollingallows you to reverse the direction of the scroll. In other words, setting it totruelets you scroll up. Note that its default value isfalse.
Since verticalScroll is a modifier, you can use it to make your custom composables scrollable.
Scrolling modifiers are a poor choice if you need to render a larger dataset or if dynamic data back your list. This is because scrollable composables compose and render all the elements inside eagerly, which can be heavy when you have many elements to display.
Like in XML, you have RecyclerView for efficiently rendering a large dynamic list; Jetpack Compose also comes with dedicated composables, which you’ll learn about in the next lesson.
Understanding the ScrollState Object
Both scrolling modifiers require a ScrollState to be passed as a parameter. To simplify this process, you can use the rememberScrollState function which creates and stores a ScrollState object for you. This object tracks the current scroll position and can be utilized with scrollable composables to alter their scroll behavior.
The crucial aspect in this context is the “remember” section, which guarantees that the scroll position remains unchanged across recompositions. This prevents the scrollable element from resetting to its default state, such as scrolling back to the top, whenever the user interface is redrawn.
The ScrollState object provides several helpful properties to manipulate the scroll behavior.
- You can use the
valueproperty to know how far the content has scrolled. - You can use the
scrollTo(value: Int)function to scroll to a specified position instantly. - You can use the
animateScrollTo(value: Int, animationSpec: AnimationSpec<Int> = default)to scroll to a specified position with an animation. - You can use the
isScrollInProgressflag to know if there is an ongoing scroll action. This can be useful for showing or hiding UI elements based on the scroll state.
These handy properties and functions let you control and customize the scroll behaviour.