Compose Pager

For now, Compose didn`t have any widget for implementing ViewPager. But thanks to Chris Banes, Manuel Vivo, Ben Trengrove, and other members who contribute to the development of “accompanist”.

Asad Mukhtar
5 min readAug 27, 2022

--

“Accompanist” is a group of libraries aiming to supplement Jetpack Compose with features commonly required by developers but not yet available.

You can explore more about Accompanist at this link https://github.com/google/accompanist

Accompanist provides many features that Compose didn`t have, like Pager (ViewPager), Swipe to Refresh, Navigation-Animations, and much more.

For this article, we are going to learn how we implement ViewPager in Compose. Before directly jumping into the development, I will show you a demo of the screen design we will build right now.

Pager is a library provided by an accompanist for implementing ViewPager in Android. Let`s add a pager dependency to your project.

repositories {
mavenCentral()
}
dependencies {
implementation "com.google.accompanist:accompanist-pager:<version>"
// for indictors implementation "com.google.accompanist:accompanist-pager-indicators:<version>"
}

For the first onBoarding screen design, we will develop a HorizontalPager. HorizontalPager is a Composable that arranges content in a horizontal row and allows the user to swipe through pages horizontally.

Horizontal Pager

In our case, we show three-page items with different content let's first create a PageItem, just copy this code and get the assets from the git repo(find the link at the end of the article).

@OptIn(ExperimentalUnitApi::class)
@Composable
fun PageItem(
@DrawableRes imageResourceId: Int,
title: String, subTitle: Int = R.string.dummy_text,
) {
Box(modifier = Modifier
.fillMaxSize()
.background(color = Color.White)) {
Image(painter = painterResource(id = imageResourceId), contentDescription = null,
modifier = Modifier
.align(Alignment.Center)
.size(250.dp))
Column(modifier = Modifier
.fillMaxWidth()
.height(150.dp)
.align(Alignment.BottomCenter),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)) {
Spacer(modifier = Modifier.height(16.dp))
Text(text = title,
textAlign = TextAlign.Center,
style = TextStyle(color = Color(0xFF5959A1),
fontSize = TextUnit(16f, TextUnitType.Sp),
fontFamily = FontFamily.Monospace))

Text(text = stringResource(subTitle),
textAlign = TextAlign.Center,
style = TextStyle(color = Color(0xFF26DAC9)),
fontSize = TextUnit(14f, TextUnitType.Sp))
}
}
}

In the above code snippet, you already have an idea about Box, Column, and modifiers.

HorizontalPager(count = 3, modifier = Modifier
.weight(0.9f, true),
state = pagerState) { page ->
when (page) {
0 -> PageItem(imageResourceId = R.drawable.ic_search, title = "CHOOSE YOUR MEAL")
1 -> PageItem(imageResourceId = R.drawable.ic_choose_payment,
title = "CHOOSE YOUR PAYMENT")
2 -> PageItem(imageResourceId = R.drawable.ic_fast_delivery,
title = "FAST DELIVERY")
}
}

HorizontalPager is a composable function provided by accompanist dependency to create a ViewPager with horizontal orientation in Compose. The original definition of HorizontalPager is below in the 0.24.13-rc version.

fun HorizontalPager(
count: Int,
modifier: Modifier = Modifier,
state: PagerState = rememberPagerState(),
reverseLayout: Boolean = false,
itemSpacing: Dp = 0.dp,
contentPadding: PaddingValues = PaddingValues(0.dp),
verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
flingBehavior: FlingBehavior = PagerDefaults.flingBehavior(
state = state,
endContentPadding = contentPadding.calculateEndPadding(LayoutDirection.Ltr),
),
key: ((page: Int) -> Any)? = null,
userScrollEnabled: Boolean = true,
content: @Composable PagerScope.(page: Int) -> Unit,
)

count: count defines the number of pages to be displayed in Viewpager. modifier: An ordered, immutable collection of modifier elements that decorate or add behavior to Compose UI elements. For example, backgrounds, padding and click event listeners decorate or add behavior to rows, text or buttons.
state: state object to be used to control or observe the pager’s state.
reverseLayout : reverse the direction of scrolling and layout, when `true` items will be composed from the end to the start and [PagerState.currentPage] == 0 will mean the first item is located at the end.
itemSpacing: horizontal spacing to add between items.
userScrollEnable: whether the scrolling via the user gestures or accessibility actions is allowed. You can still scroll programmatically using the state even when it is disabled.

you can explore other parms…

For dots, you can copy the below code snippet.

// pagerState is object that holds the states of  HorizontalPagerHorizontalPagerIndicator(pagerState = pagerState,
activeColor = Color(0xFF00F7FF),
inactiveColor = Color(0xFFAFB2B3))

Here is the below gif you will develop a vertical ViewPager:

For Vertical Pager, I use the same PageItem so just copy the below snippet and align it as according to your requirements.

VerticalPager(count = 3, modifier = Modifier.align(Alignment.Center),
state = pagerState) { page ->
when (page) {
0 -> PageItem(imageResourceId = R.drawable.ic_search, title = "CHOOSE YOUR MEAL")
1 -> PageItem(imageResourceId = R.drawable.ic_choose_payment,
title = "CHOOSE YOUR PAYMENT")
2 -> PageItem(imageResourceId = R.drawable.ic_fast_delivery,
title = "FAST DELIVERY")
}
}

VerticalPager is a Composable that arranges content in a verticaal column and allows the user to swipe through pages vertically.The original definition of HorizontalPager is below in the 0.24.13-rc version.

fun VerticalPager(
count: Int,
modifier: Modifier = Modifier,
state: PagerState = rememberPagerState(),
reverseLayout: Boolean = false,
itemSpacing: Dp = 0.dp,
contentPadding: PaddingValues = PaddingValues(0.dp),
horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
flingBehavior: FlingBehavior = PagerDefaults.flingBehavior(
state = state,
endContentPadding = contentPadding.calculateBottomPadding(),
),
key: ((page: Int) -> Any)? = null,
userScrollEnabled: Boolean = true,
content: @Composable PagerScope.(page: Int) -> Unit,
)

For dots, you can copy the below code snippet.

VerticalPagerIndicator(pagerState = pagerState,
activeColor = Color(0xFF00F7FF),
inactiveColor = Color(0xFFAFB2B3))

As you can see most of the params in HorizontalPager, and VerticalPager Composable function is the same, below snippet of code taken from Pager. kt to let you know about how the accompanist pager works under the hood.

if (isVertical) {
LazyColumn(
state = state.lazyListState,
verticalArrangement = Arrangement.spacedBy(itemSpacing, verticalAlignment),
horizontalAlignment = horizontalAlignment,
flingBehavior = flingBehavior,
reverseLayout = reverseLayout,
contentPadding = contentPadding,
userScrollEnabled = userScrollEnabled,
modifier = modifier,
) {
items(
count = count,
key = key,
) { page ->
Box(
Modifier
.nestedScroll(connection = consumeFlingNestedScrollConnection)
.fillParentMaxHeight()
.wrapContentSize()
) {
pagerScope.content(page)
}
}
}
} else {
LazyRow(
state = state.lazyListState,
verticalAlignment = verticalAlignment,
horizontalArrangement = Arrangement.spacedBy(itemSpacing, horizontalAlignment),
flingBehavior = flingBehavior,
reverseLayout = reverseLayout,
contentPadding = contentPadding,
userScrollEnabled = userScrollEnabled,
modifier = modifier,
) {
items(
count = count,
key = key,
) { page ->
Box(
Modifier
.nestedScroll(connection = consumeFlingNestedScrollConnection)
.fillParentMaxWidth()
.wrapContentSize()
) {
pagerScope.content(page)
}
}
}
}

Here you can find the git repo related to this article: https://github.com/asadmukhtar28/Compose-Pager

Thanks for reading, share your love by pressing the clap button and sharing this article with your other connections.

Follow me for more Android, Java, Kotlin related content.

You can connect with me on Github Linkedin and Twitter :)

--

--