diff --git a/gradle.properties b/gradle.properties index 1d3e9599c..b5eaff080 100644 --- a/gradle.properties +++ b/gradle.properties @@ -33,7 +33,7 @@ systemProp.org.gradle.internal.http.socketTimeout=120000 GROUP=com.google.accompanist # !! No longer need to update this manually when using a Compose SNAPSHOT -VERSION_NAME=0.24.11-SNAPSHOT +VERSION_NAME=0.24.13-SNAPSHOT POM_DESCRIPTION=Utilities for Jetpack Compose diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 076ef88c6..12babc1e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -compose = "1.2.0-beta03" +compose = "1.2.0-rc02" composesnapshot = "-" # a single character = no snapshot # gradlePlugin and lint need to be updated together @@ -13,7 +13,7 @@ okhttp = "3.12.13" coil = "1.3.2" androidxtest = "1.4.0" -androidxnavigation = "2.5.0-rc01" +androidxnavigation = "2.5.0-rc02" [libraries] compose-ui-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" } @@ -28,7 +28,7 @@ compose-material-material = { module = "androidx.compose.material:material", ver compose-material-iconsext = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" } compose-animation-animation = { module = "androidx.compose.animation:animation", version.ref = "compose" } -snapper = "dev.chrisbanes.snapper:snapper:0.2.0" +snapper = "dev.chrisbanes.snapper:snapper:0.2.2" android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "gradlePlugin" } gradleMavenPublishPlugin = "com.vanniktech:gradle-maven-publish-plugin:0.17.0" @@ -88,4 +88,4 @@ android-tools-lint-lint = { module = "com.android.tools.lint:lint", version.ref android-tools-lint-api = { module = "com.android.tools.lint:lint-api", version.ref = "lintMinCompose" } android-tools-lint-tests = { module = "com.android.tools.lint:lint-tests", version.ref = "lintMinCompose" } -squareup-mockwebserver = "com.squareup.okhttp3:mockwebserver:4.9.3" \ No newline at end of file +squareup-mockwebserver = "com.squareup.okhttp3:mockwebserver:4.9.3" 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