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

ScrollState

public final class ScrollState implements ScrollableState


State of the scroll. Allows the developer to change the scroll position or get current state by calling methods on this object. To be hosted and passed to Modifier.verticalScroll or Modifier.horizontalScroll

To create and automatically remember ScrollState with default parameters use rememberScrollState.

Learn how to control the state of Modifier.verticalScroll or Modifier.horizontalScroll:

import androidx.compose.foundation.gestures.animateScrollBy
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.Text
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier

// Create ScrollState to own it and be able to control scroll behaviour of scrollable Row below
val scrollState = rememberScrollState()
val scope = rememberCoroutineScope()
Column {
    Row(Modifier.horizontalScroll(scrollState)) {
        repeat(1000) { index ->
            Square(index)
        }
    }
    // Controls for scrolling
    Row(verticalAlignment = Alignment.CenterVertically) {
        Text("Scroll")
        Button(
            onClick = {
                scope.launch { scrollState.scrollTo(scrollState.value - 1000) }
            }
        ) {
            Text("< -")
        }
        Button(
            onClick = {
                scope.launch { scrollState.scrollBy(10000f) }
            }
        ) {
            Text("--- >")
        }
    }
    Row(verticalAlignment = Alignment.CenterVertically) {
        Text("Smooth Scroll")
        Button(
            onClick = {
                scope.launch { scrollState.animateScrollTo(scrollState.value - 1000) }
            }
        ) {
            Text("< -")
        }
        Button(
            onClick = {
                scope.launch { scrollState.animateScrollBy(10000f) }
            }
        ) {
            Text("--- >")
        }
    }
}

Summary

Nested types

public static class ScrollState.Companion

Public constructors

ScrollState(int initial)

Public methods

final void
animateScrollTo(
    int value,
    @NonNull AnimationSpec<@NonNull Float> animationSpec
)

Scroll to position in pixels with animation.

float
dispatchRawDelta(float delta)

Dispatch scroll delta in pixels avoiding all scroll related mechanisms.

boolean

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

boolean

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

final @NonNull InteractionSource

InteractionSource that will be used to dispatch drag events when this list is being dragged.

final int

maximum bound for value, or Int.MAX_VALUE if still unknown

final int

current scroll position value in pixels

boolean

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

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.

final float
scrollTo(int value)

Instantly jump to the given position in pixels.

Public constructors

ScrollState

public ScrollState(int initial)
Parameters
int initial

value of the scroll

Public methods

animateScrollTo

public final void animateScrollTo(
    int value,
    @NonNull AnimationSpec<@NonNull Float> animationSpec
)

Scroll to position in pixels with animation.

Parameters
int value

target value in pixels to smooth scroll to, value will be coerced to 0..maxPosition

@NonNull AnimationSpec<@NonNull Float> animationSpec

animation curve for smooth scroll animation

dispatchRawDelta

public 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

public 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

public 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
    )
}

getInteractionSource

public final @NonNull InteractionSource getInteractionSource()

InteractionSource that will be used to dispatch drag events when this list is being dragged. If you want to know whether the fling (or smooth scroll) is in progress, use isScrollInProgress.

getMaxValue

public final int getMaxValue()

maximum bound for value, or Int.MAX_VALUE if still unknown

getValue

public final int getValue()

current scroll position value in pixels

isScrollInProgress

public boolean isScrollInProgress()

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

scroll

public 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.

scrollTo

public final float scrollTo(int value)

Instantly jump to the given position in pixels.

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

Parameters
int value

number of pixels to scroll by

Returns
float

the amount of scroll consumed

See also
animateScrollTo

for an animated version