{% setvar book_path %}/reference/androidx/_book.yaml{% endsetvar %} {% include "_shared/_reference-head-tags.html" %}

ScrollableState

public interface ScrollableState

Known direct subclasses
LazyGridState

A state object that can be hoisted to control and observe scrolling.

LazyListState

A state object that can be hoisted to control and observe scrolling.

LazyStaggeredGridState

Hoisted state object controlling LazyVerticalStaggeredGrid or LazyHorizontalStaggeredGrid.

PagerState

The state that can be used to control VerticalPager and HorizontalPager

ScrollState

State of the scroll.


An object representing something that can be scrolled. This interface is implemented by states of scrollable containers such as androidx.compose.foundation.lazy.LazyListState or androidx.compose.foundation.ScrollState in order to provide low-level scrolling control via scroll, as well as allowing for higher-level scrolling functions like animateScrollBy to be implemented as extension functions on ScrollableState.

Subclasses may also have their own methods that are specific to their interaction paradigm, such as androidx.compose.foundation.lazy.LazyListState.scrollToItem.

See also
animateScrollBy
scrollable

Summary

Public methods

abstract float
dispatchRawDelta(float delta)

Dispatch scroll delta in pixels avoiding all scroll related mechanisms.

default boolean

Whether this ScrollableState can scroll backward (consume a negative delta).

default boolean

Whether this ScrollableState can scroll forward (consume a positive delta).

abstract boolean

Whether this ScrollableState is currently scrolling by gesture, fling or programmatically or not.

abstract void
scroll(
    @NonNull MutatePriority scrollPriority,
    @ExtensionFunctionType @NonNull SuspendFunction1<@NonNull ScrollScopeUnit> block
)

Call this function to take control of scrolling and gain the ability to send scroll events via ScrollScope.scrollBy.

Extension functions

default final float
ScrollExtensionsKt.animateScrollBy(
    @NonNull ScrollableState receiver,
    float value,
    @NonNull AnimationSpec<@NonNull Float> animationSpec
)

Scroll by value pixels with animation.

default final float
ScrollExtensionsKt.scrollBy(
    @NonNull ScrollableState receiver,
    float value
)

Jump instantly by value pixels.

default final void
ScrollExtensionsKt.stopScroll(
    @NonNull ScrollableState receiver,
    @NonNull MutatePriority scrollPriority
)

Stop and suspend until any ongoing animation, smooth scrolling, fling, or any other scroll occurring via ScrollableState.scroll is terminated.

Public methods

dispatchRawDelta

abstract float dispatchRawDelta(float delta)

Dispatch scroll delta in pixels avoiding all scroll related mechanisms.

NOTE: unlike scroll, dispatching any delta with this method won't trigger nested scroll, won't stop ongoing scroll/drag animation and will bypass scrolling of any priority. This method will also ignore reverseDirection and other parameters set in scrollable.

This method is used internally for nested scrolling dispatch and other low level operations, allowing implementers of ScrollableState influence the consumption as suits them. Manually dispatching delta via this method will likely result in a bad user experience, you must prefer scroll method over this one.

Parameters
float delta

amount of scroll dispatched in the nested scroll process

Returns
float

the amount of delta consumed

getCanScrollBackward

default boolean getCanScrollBackward()

Whether this ScrollableState can scroll backward (consume a negative delta). This is typically false if the scroll position is equal to its minimum value, and true otherwise.

Note that true here does not imply that delta will be consumed - the ScrollableState may decide not to handle the incoming delta (such as if it is already being scrolled separately). Additionally, for backwards compatibility with previous versions of ScrollableState this value defaults to true.

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer

val state = rememberLazyListState()
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
    Icon(
        Icons.Filled.KeyboardArrowUp,
        null,
        Modifier.graphicsLayer {
            // Hide the icon if we cannot scroll backward (we are the start of the list)
            // We use graphicsLayer here to control the alpha so that we only redraw when this
            // value changes, instead of recomposing
            alpha = if (state.canScrollBackward) 1f else 0f
        },
        Color.Red
    )
    val items = (1..100).toList()
    LazyColumn(
        Modifier
            .weight(1f)
            .fillMaxWidth(), state
    ) {
        items(items) {
            Text("Item is $it")
        }
    }
    Icon(
        Icons.Filled.KeyboardArrowDown,
        null,
        Modifier.graphicsLayer {
            // Hide the icon if we cannot scroll forward (we are the end of the list)
            // We use graphicsLayer here to control the alpha so that we only redraw when this
            // value changes, instead of recomposing
            alpha = if (state.canScrollForward) 1f else 0f
        },
        Color.Red
    )
}

getCanScrollForward

default boolean getCanScrollForward()

Whether this ScrollableState can scroll forward (consume a positive delta). This is typically false if the scroll position is equal to its maximum value, and true otherwise.

Note that true here does not imply that delta will be consumed - the ScrollableState may decide not to handle the incoming delta (such as if it is already being scrolled separately). Additionally, for backwards compatibility with previous versions of ScrollableState this value defaults to true.

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer

val state = rememberLazyListState()
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
    Icon(
        Icons.Filled.KeyboardArrowUp,
        null,
        Modifier.graphicsLayer {
            // Hide the icon if we cannot scroll backward (we are the start of the list)
            // We use graphicsLayer here to control the alpha so that we only redraw when this
            // value changes, instead of recomposing
            alpha = if (state.canScrollBackward) 1f else 0f
        },
        Color.Red
    )
    val items = (1..100).toList()
    LazyColumn(
        Modifier
            .weight(1f)
            .fillMaxWidth(), state
    ) {
        items(items) {
            Text("Item is $it")
        }
    }
    Icon(
        Icons.Filled.KeyboardArrowDown,
        null,
        Modifier.graphicsLayer {
            // Hide the icon if we cannot scroll forward (we are the end of the list)
            // We use graphicsLayer here to control the alpha so that we only redraw when this
            // value changes, instead of recomposing
            alpha = if (state.canScrollForward) 1f else 0f
        },
        Color.Red
    )
}

isScrollInProgress

abstract boolean isScrollInProgress()

Whether this ScrollableState is currently scrolling by gesture, fling or programmatically or not.

scroll

abstract void scroll(
    @NonNull MutatePriority scrollPriority,
    @ExtensionFunctionType @NonNull SuspendFunction1<@NonNull ScrollScopeUnit> block
)

Call this function to take control of scrolling and gain the ability to send scroll events via ScrollScope.scrollBy. All actions that change the logical scroll position must be performed within a scroll block (even if they don't call any other methods on this object) in order to guarantee that mutual exclusion is enforced.

If scroll is called from elsewhere with the scrollPriority higher or equal to ongoing scroll, ongoing scroll will be canceled.

Extension functions

ScrollExtensionsKt.animateScrollBy

default final float ScrollExtensionsKt.animateScrollBy(
    @NonNull ScrollableState receiver,
    float value,
    @NonNull AnimationSpec<@NonNull Float> animationSpec
)

Scroll by value pixels with animation.

Cancels the currently running scroll, if any, and suspends until the cancellation is complete.

Parameters
float value

number of pixels to scroll by

@NonNull AnimationSpec<@NonNull Float> animationSpec

AnimationSpec to be used for this scrolling

Returns
float

the amount of scroll consumed

ScrollExtensionsKt.scrollBy

default final float ScrollExtensionsKt.scrollBy(
    @NonNull ScrollableState receiver,
    float value
)

Jump instantly by value pixels.

Cancels the currently running scroll, if any, and suspends until the cancellation is complete.

Parameters
float value

number of pixels to scroll by

Returns
float

the amount of scroll consumed

See also
animateScrollBy

for an animated version

ScrollExtensionsKt.stopScroll

default final void ScrollExtensionsKt.stopScroll(
    @NonNull ScrollableState receiver,
    @NonNull MutatePriority scrollPriority
)

Stop and suspend until any ongoing animation, smooth scrolling, fling, or any other scroll occurring via ScrollableState.scroll is terminated.

Parameters
@NonNull MutatePriority scrollPriority

scrolls that run with this priority or lower will be stopped