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

PagerState

@ExperimentalFoundationApi
public abstract class PagerState implements ScrollableState


The state that can be used to control VerticalPager and HorizontalPager

Summary

Public constructors

PagerState(int initialPage, float initialPageOffsetFraction)

Public methods

final void
animateScrollToPage(
    int page,
    float pageOffsetFraction,
    @NonNull AnimationSpec<@NonNull Float> animationSpec
)

Scroll animate to a given page.

float
dispatchRawDelta(float delta)

Dispatch scroll delta in pixels avoiding all scroll related mechanisms.

final boolean

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

final boolean

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

final int

The page that sits closest to the snapped position.

final float

Indicates how far the current page is to the snapped position, this will vary from -0.5 (page is offset towards the start of the layout) to 0.5 (page is offset towards the end of the layout).

final int

The initial page to be displayed

final float

The offset of the initial page with respect to the start of the layout.

final @NonNull InteractionSource

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

final float

An utility function to help to calculate a given page's offset.

abstract int

The total amount of pages present in this pager

final int

The page that is currently "settled".

final int

The page this Pager intends to settle to.

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 void
scrollToPage(int page, float pageOffsetFraction)

Scroll (jump immediately) to a given page.

Public constructors

PagerState

public PagerState(int initialPage, float initialPageOffsetFraction)
Parameters
int initialPage

The initial page to be displayed

float initialPageOffsetFraction

The offset of the initial page with respect to the start of the layout.

Public methods

animateScrollToPage

public final void animateScrollToPage(
    int page,
    float pageOffsetFraction,
    @NonNull AnimationSpec<@NonNull Float> animationSpec
)

Scroll animate to a given page. If the page is too far away from currentPage we will not compose all pages in the way. We will pre-jump to a nearer page, compose and animate the rest of the pages until page.

Please refer to the sample to learn how to use this API.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

val state = rememberPagerState { 10 }
val animationScope = rememberCoroutineScope()
Column {
    HorizontalPager(
        modifier = Modifier.weight(0.7f),
        state = state
    ) { page ->
        Box(
            modifier = Modifier
                .padding(10.dp)
                .background(Color.Blue)
                .fillMaxWidth()
                .aspectRatio(1f),
            contentAlignment = Alignment.Center
        ) {
            Text(text = page.toString(), fontSize = 32.sp)
        }
    }

    Box(
        modifier = Modifier
            .weight(0.3f)
            .fillMaxWidth(), contentAlignment = Alignment.Center
    ) {
        Button(onClick = {
            animationScope.launch {
                state.animateScrollToPage(state.currentPage + 1)
            }
        }) {
            Text(text = "Next Page")
        }
    }
}
Parameters
int page

The destination page to scroll to

float pageOffsetFraction

A fraction of the page size that indicates the offset the destination page will be offset from its snapped position.

@NonNull AnimationSpec<@NonNull Float> animationSpec

An AnimationSpec to move between pages. We'll use a spring as the default 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 final 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 final 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
    )
}

getCurrentPage

public final int getCurrentPage()

The page that sits closest to the snapped position. This is an observable value and will change as the pager scrolls either by gesture or animation.

Please refer to the sample to learn how to use this API.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

val pagerState = rememberPagerState { 10 }
Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
        modifier = Modifier.weight(0.9f),
        state = pagerState
    ) { page ->
        Box(
            modifier = Modifier
                .padding(10.dp)
                .background(Color.Blue)
                .fillMaxWidth()
                .aspectRatio(1f),
            contentAlignment = Alignment.Center
        ) {
            Text(text = page.toString(), fontSize = 32.sp)
        }
    }
    Column(
        modifier = Modifier
            .weight(0.1f)
            .fillMaxWidth()
    ) {
        Text(text = "Current Page: ${pagerState.currentPage}")
        Text(text = "Target Page: ${pagerState.targetPage}")
        Text(text = "Settled Page Offset: ${pagerState.settledPage}")
    }
}

getCurrentPageOffsetFraction

public final float getCurrentPageOffsetFraction()

Indicates how far the current page is to the snapped position, this will vary from -0.5 (page is offset towards the start of the layout) to 0.5 (page is offset towards the end of the layout). This is 0.0 if the currentPage is in the snapped position. The value will flip once the current page changes.

This property is observable and shouldn't be used as is in a composable function due to potential performance issues. To use it in the composition, please consider using a derived state (e.g derivedStateOf) to only have recompositions when the derived value changes.

Please refer to the sample to learn how to use this API.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

val pagerState = rememberPagerState { 10 }
Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
        modifier = Modifier.weight(0.9f),
        state = pagerState
    ) { page ->
        Box(
            modifier = Modifier
                .padding(10.dp)
                .background(Color.Blue)
                .fillMaxWidth()
                .aspectRatio(1f),
            contentAlignment = Alignment.Center
        ) {
            Text(text = page.toString(), fontSize = 32.sp)
        }
    }
    Column(
        modifier = Modifier
            .weight(0.1f)
            .fillMaxWidth()
    ) {
        Text(text = "Current Page: ${pagerState.currentPage}")
        Text(text = "Target Page: ${pagerState.targetPage}")
        Text(text = "Settled Page Offset: ${pagerState.settledPage}")
    }
}

getInitialPage

public final int getInitialPage()

The initial page to be displayed

getInitialPageOffsetFraction

public final float getInitialPageOffsetFraction()

The offset of the initial page with respect to the start of the layout.

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 animated scroll) is in progress, use isScrollInProgress.

getOffsetFractionForPage

public final float getOffsetFractionForPage(int page)

An utility function to help to calculate a given page's offset. Since this is based off currentPageOffsetFraction the same concept applies: a fraction offset that represents how far page is from the settled position (represented by currentPage offset). The difference here is that currentPageOffsetFraction is a value between -0.5 and 0.5 and the value calculate by this function can be larger than these numbers if page is different than currentPage.

Parameters
int page

The page to calculate the offset from. This should be between 0 and pageCount.

Returns
float

The offset of page with respect to currentPage.

getPageCount

public abstract int getPageCount()

The total amount of pages present in this pager

getSettledPage

public final int getSettledPage()

The page that is currently "settled". This is an animation/gesture unaware page in the sense that it will not be updated while the pages are being scrolled, but rather when the animation/scroll settles.

Please refer to the sample to learn how to use this API.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

val pagerState = rememberPagerState { 10 }
Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
        modifier = Modifier.weight(0.9f),
        state = pagerState
    ) { page ->
        Box(
            modifier = Modifier
                .padding(10.dp)
                .background(Color.Blue)
                .fillMaxWidth()
                .aspectRatio(1f),
            contentAlignment = Alignment.Center
        ) {
            Text(text = page.toString(), fontSize = 32.sp)
        }
    }
    Column(
        modifier = Modifier
            .weight(0.1f)
            .fillMaxWidth()
    ) {
        Text(text = "Current Page: ${pagerState.currentPage}")
        Text(text = "Target Page: ${pagerState.targetPage}")
        Text(text = "Settled Page Offset: ${pagerState.settledPage}")
    }
}

getTargetPage

public final int getTargetPage()

The page this Pager intends to settle to. During fling or animated scroll (from animateScrollToPage this will represent the page this pager intends to settle to. When no scroll is ongoing, this will be equal to currentPage.

Please refer to the sample to learn how to use this API.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

val pagerState = rememberPagerState { 10 }
Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
        modifier = Modifier.weight(0.9f),
        state = pagerState
    ) { page ->
        Box(
            modifier = Modifier
                .padding(10.dp)
                .background(Color.Blue)
                .fillMaxWidth()
                .aspectRatio(1f),
            contentAlignment = Alignment.Center
        ) {
            Text(text = page.toString(), fontSize = 32.sp)
        }
    }
    Column(
        modifier = Modifier
            .weight(0.1f)
            .fillMaxWidth()
    ) {
        Text(text = "Current Page: ${pagerState.currentPage}")
        Text(text = "Target Page: ${pagerState.targetPage}")
        Text(text = "Settled Page Offset: ${pagerState.settledPage}")
    }
}

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.

scrollToPage

public final void scrollToPage(int page, float pageOffsetFraction)

Scroll (jump immediately) to a given page.

Please refer to the sample to learn how to use this API.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

val state = rememberPagerState { 10 }
val scrollScope = rememberCoroutineScope()
Column {
    HorizontalPager(
        modifier = Modifier.height(400.dp),
        state = state
    ) { page ->
        Box(
            modifier = Modifier
                .padding(10.dp)
                .background(Color.Blue)
                .fillMaxWidth()
                .aspectRatio(1f),
            contentAlignment = Alignment.Center
        ) {
            Text(text = page.toString(), fontSize = 32.sp)
        }
    }

    Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
        androidx.compose.material.Button(onClick = {
            scrollScope.launch {
                state.scrollToPage(state.currentPage + 1)
            }
        }) {
            Text(text = "Next Page")
        }
    }
}
Parameters
int page

The destination page to scroll to

float pageOffsetFraction

A fraction of the page size that indicates the offset the destination page will be offset from its snapped position.