diff --git a/pager-indicators/api/current.api b/pager-indicators/api/current.api index e4c8947c3..1ea8a99c0 100644 --- a/pager-indicators/api/current.api +++ b/pager-indicators/api/current.api @@ -7,7 +7,7 @@ package com.google.accompanist.pager { } public final class PagerTabKt { - method @com.google.accompanist.pager.ExperimentalPagerApi public static androidx.compose.ui.Modifier pagerTabIndicatorOffset(androidx.compose.ui.Modifier, com.google.accompanist.pager.PagerState pagerState, java.util.List tabPositions); + method @com.google.accompanist.pager.ExperimentalPagerApi public static androidx.compose.ui.Modifier pagerTabIndicatorOffset(androidx.compose.ui.Modifier, com.google.accompanist.pager.PagerState pagerState, java.util.List tabPositions, optional kotlin.jvm.functions.Function1 pageIndexMapping); } } diff --git a/pager-indicators/src/main/java/com/google/accompanist/pager/PagerTab.kt b/pager-indicators/src/main/java/com/google/accompanist/pager/PagerTab.kt index f093dbaf2..529035c46 100644 --- a/pager-indicators/src/main/java/com/google/accompanist/pager/PagerTab.kt +++ b/pager-indicators/src/main/java/com/google/accompanist/pager/PagerTab.kt @@ -34,12 +34,13 @@ import androidx.compose.ui.unit.lerp fun Modifier.pagerTabIndicatorOffset( pagerState: PagerState, tabPositions: List, + pageIndexMapping: (Int) -> Int = { it }, ): Modifier = layout { measurable, constraints -> if (tabPositions.isEmpty()) { // If there are no pages, nothing to show layout(constraints.maxWidth, 0) {} } else { - val currentPage = minOf(tabPositions.lastIndex, pagerState.currentPage) + val currentPage = minOf(tabPositions.lastIndex, pageIndexMapping(pagerState.currentPage)) val currentTab = tabPositions[currentPage] val previousTab = tabPositions.getOrNull(currentPage - 1) val nextTab = tabPositions.getOrNull(currentPage + 1) diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 0c1872fc8..9d44a7069 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -147,6 +147,16 @@ + + + + + + + + val pages = remember { + listOf("Home", "Shows", "Movies", "Books", "Really long movies", "Short audiobooks") + } + + Column( + Modifier + .fillMaxSize() + .padding(padding) + ) { + val coroutineScope = rememberCoroutineScope() + + // We start the pager in the middle of the raw number of pages + val loopingCount = Int.MAX_VALUE + val startIndex = loopingCount / 2 + val pagerState = rememberPagerState(initialPage = startIndex) + + fun pageMapper(index: Int): Int { + return (index - startIndex).floorMod(pages.count()) + } + + val currentIndex by remember { + derivedStateOf { pageMapper(pagerState.currentPage) } + } + + ScrollableTabRow( + // Our selected tab is our current page + selectedTabIndex = currentIndex, + indicator = { tabPositions -> + TabRowDefaults.Indicator( + Modifier.pagerTabIndicatorOffset(pagerState, tabPositions, ::pageMapper) + ) + } + ) { + // Add tabs for all of our pages + pages.forEachIndexed { index, title -> + Tab( + text = { Text(title) }, + selected = currentIndex == index, + onClick = { + // Animate to the selected page when clicked + coroutineScope.launch { + when { + currentIndex > index -> { + pagerState.animateScrollToPage( + page = pagerState.currentPage - (currentIndex - index) + ) + } + currentIndex < index -> { + pagerState.animateScrollToPage( + page = pagerState.currentPage + (index - currentIndex) + ) + } + } + } + } + ) + } + } + + HorizontalPager( + count = loopingCount, + state = pagerState, + // Add 16.dp padding to 'center' the pages + contentPadding = PaddingValues(16.dp), + modifier = Modifier + .weight(1f) + .fillMaxWidth() + ) { index -> + val page = pageMapper(index) + Card { + Box(Modifier.fillMaxSize()) { + Text( + text = "Page: ${pages[page]}", + style = MaterialTheme.typography.h4, + modifier = Modifier.align(Alignment.Center) + ) + } + } + } + } + } +} + +private fun Int.floorMod(other: Int): Int = when (other) { + 0 -> this + else -> this - floorDiv(other) * other +} diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index c28fce9a4..27d3b6d69 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -28,6 +28,7 @@ Horizontal Pager: Transition Horizontal Pager: Looping Horizontal Pager: Looping with Indicators + Horizontal Pager: Looping with Tabs Horizontal Pager: Tabs Horizontal Pager: Scrolling content Horizontal Pager: Different paddings