« Horizontal and Vertical ViewPager in Jetpack Compose
In Jetpack Compose
we don’t have anything by default like ViewPager
that we could use, but we have a solution for that. We are going to use Accompanist Pager library
. First, we are gonna add the dependency to the app-level build.gradle file:
1implementation "com.google.accompanist:accompanist-pager:0.28.0"
There are two pagers avaiable
- HorizontalPager
- VerticalPager
HorizontalPager
HorizontalPager is composable where content is ordered horizontally and displayed as pages. We are going to create a data class called HorizontalPagerContent which will represent horizontal pager content.
1data class HorizontalPagerContent(2 val title: String,3 val subtitle: String,4 val description: String5)
Next is to create a list of items that will be shown in this pager:
1fun createItems() = listOf(2 HorizontalPagerContent(title = "Title1", subtitle = "Subtitle1", description = "Description1"),3 HorizontalPagerContent(title = "Title2", subtitle = "Subtitle2", description = "Description2"),4 HorizontalPagerContent(title = "Title3", subtitle = "Subtitle3", description = "Description3"),5 HorizontalPagerContent(title = "Title4", subtitle = "Subtitle4", description = "Description4"),6 HorizontalPagerContent(title = "Title5", subtitle = "Subtitle5", description = "Description5")7)
HorizontalPager
has two mandatory parameters and they are count
: Int and content: @Composable PagerScope.(page: Int) -> Unit. One optional parameter is
state`: PagerState which represents the state of the pager. That state you can use to get the current page, page count, and to scroll to the specific page.
1@OptIn(ExperimentalPagerApi::class)2@Composable3fun HorizontalPagerScreen() {4 Column(5 modifier = Modifier6 .fillMaxSize()7 .padding(30.dp)8 ) {9 val items = createItems()10 val pagerState = rememberPagerState()1112 HorizontalPager(13 count = items.size,14 state = pagerState,15 modifier = Modifier.weight(1f)16 ) { currentPage ->17 Column(18 modifier = Modifier.fillMaxSize()19 ) {20 Text(21 text = items[currentPage].title,22 style = MaterialTheme.typography.h223 )24 Spacer(modifier = Modifier.height(10.dp))25 Text(26 text = items[currentPage].subtitle,27 style = MaterialTheme.typography.h428 )29 Spacer(modifier = Modifier.height(10.dp))30 Text(31 text = items[currentPage].description,32 style = MaterialTheme.typography.body133 )34 }35 }3637 val coroutineScope = rememberCoroutineScope()38 Button(39 onClick = {40 coroutineScope.launch {41 pagerState.animateScrollToPage(page = 2)42 }43 },44 modifier = Modifier.align(Alignment.CenterHorizontally)45 ) {46 Text(text = "Scroll to the third page")47 }48 }49}
At the end of our main composable, we can see a button that will, when pressed, scroll to the third page.
The next thing that we are gonna add is indicators and tabs. For that we need to add a new accompanist library:
1implementation "com.google.accompanist:accompanist-pager-indicators:0.28.0"
Adding indicators is very simple, we just need to add HorizontalPagerIndicator
and pass pagerState
.
1HorizontalPagerIndicator(2 pagerState = pagerState,3 modifier = Modifier4 .align(Alignment.CenterHorizontally)5 .padding(16.dp),6)
Now let’s add tabs, we are going to create a new composable called HorizontalTabs, and in that composable, we will use TabRow
and Tab
.
1@OptIn(ExperimentalPagerApi::class)2@Composable3fun HorizontalTabs(4 items: List<HorizontalPagerContent>,5 pagerState: PagerState,6 scope: CoroutineScope7) {8 TabRow(9 selectedTabIndex = pagerState.currentPage,10 indicator = { tabPositions ->11 TabRowDefaults.Indicator(12 modifier = Modifier.pagerTabIndicatorOffset(pagerState, tabPositions)13 )14 }15 ) {16 items.forEachIndexed { index, item ->17 Tab(18 selected = pagerState.currentPage == index,19 onClick = {20 scope.launch {21 pagerState.animateScrollToPage(page = index)22 }23 }24 ) {25 Text(text = item.title)26 }27 }28 }29}
VerticalPager
VerticalPager is composable where content is ordered vertically and displayed as pages.
Implementing VerticalPager is basically the same thing as implementing HorizontalPager.
You just need to use VerticalPager
instead of HorizontalPager
and for indicators you use VerticalPagerIndicator
instead of HorizontalPagerIndicator
.
1@OptIn(ExperimentalPagerApi::class)2@Composable3fun VerticalPagerScreen() {4 Column(5 modifier = Modifier6 .fillMaxSize()7 .padding(30.dp)8 ) {9 val items = createItems()10 val pagerState = rememberPagerState()11 val coroutineScope = rememberCoroutineScope()1213 Row(14 modifier = Modifier.weight(1f)15 ) {16 VerticalPager(17 count = items.size,18 state = pagerState,19 modifier = Modifier.weight(1f)20 ) { currentPage ->21 Column(22 modifier = Modifier.fillMaxSize()23 ) {24 Text(25 text = items[currentPage].title,26 style = MaterialTheme.typography.h227 )28 Spacer(modifier = Modifier.height(10.dp))29 Text(30 text = items[currentPage].subtitle,31 style = MaterialTheme.typography.h432 )33 Spacer(modifier = Modifier.height(10.dp))34 Text(35 text = items[currentPage].description,36 style = MaterialTheme.typography.body137 )38 }39 }4041 VerticalPagerIndicator(42 pagerState = pagerState,43 modifier = Modifier44 .align(Alignment.CenterVertically)45 .padding(16.dp),46 )47 }4849 Button(50 onClick = {51 coroutineScope.launch {52 pagerState.animateScrollToPage(page = 2)53 }54 },55 modifier = Modifier.align(Alignment.CenterHorizontally)56 ) {57 Text(text = "Scroll to the third page")58 }59 }60}
For full class code to try out the code yourself: