Reputation: 3748
I am working on sample where I want to display items using HorizontalPager. I am able to display pages horizontally scrollable without issues. Also able to place indicators using HorizontalPagerIndicator.
Issue: When I click on pager Indicator I am able to navigate forward without any issues. I have 4 pages , when clicked on zerothIndicator , page is scrolled to zeroth indicator, when clicked on 1st indicator page is scrolled to 1st page, when again clicked on zeroth Indicator instead of scrolling to Zeroth page , its scrolled to 2nd page. I am not able to track the position of clicked indicator. Is there a way can we track the position of clicked indicator. Please find my code below for reference:
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun HorizontalPagerWithIndicators(deals: List<Deal>) {
val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
Column{
HorizontalPager(pageCount = deals.size, state = pagerState,
contentPadding = PaddingValues(horizontal = 20.dp), pageSpacing = 10.dp) { page ->
Column() {
DisplayDeal(deal = deals[page])
Box(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 10.dp, bottom = 10.dp)
) {
HorizontalPagerIndicator(
pageCount = deals.size,
pagerState = pagerState,
modifier = Modifier.align(Alignment.Center).clickable {
val currentPage = pagerState.currentPage
val totalPages = deals.size
val nextPage = if (currentPage < totalPages - 1) currentPage + 1 else 0
coroutineScope.launch { pagerState.animateScrollToPage(nextPage) }
}
)
}
}
}
}
}
Below are the dependencies used:
implementation 'androidx.compose.foundation:foundation:1.4.3'
implementation "com.google.accompanist:accompanist-pager-indicators:0.30.1"
Please help me in resolving this issue.
Thanks in Advance.
Upvotes: 3
Views: 2808
Reputation: 21
You can just copy and modify the implementation of HorizontalPagerIndicator
.
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ClickableHorizontalPagerIndicator(
pagerState: androidx.compose.foundation.pager.PagerState,
pageCount: Int,
modifier: Modifier = Modifier,
pageIndexMapping: (Int) -> Int = { it },
activeColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
inactiveColor: Color = activeColor.copy(ContentAlpha.disabled),
indicatorWidth: Dp = 8.dp,
indicatorHeight: Dp = indicatorWidth,
spacing: Dp = indicatorWidth,
indicatorShape: Shape = CircleShape,
) {
val scope = rememberCoroutineScope()
val stateBridge = remember(pagerState) {
object : PagerStateBridge {
override val currentPage: Int
get() = pagerState.currentPage
override val currentPageOffset: Float
get() = pagerState.currentPageOffsetFraction
}
}
HorizontalPagerIndicator(
pagerState = stateBridge,
pageCount = pageCount,
modifier = modifier,
pageIndexMapping = pageIndexMapping,
activeColor = activeColor,
inactiveColor = inactiveColor,
indicatorHeight = indicatorHeight,
indicatorWidth = indicatorWidth,
spacing = spacing,
indicatorShape = indicatorShape,
) {
scope.launch {
pagerState.animateScrollToPage(it)
}
}
}
@Composable
private fun HorizontalPagerIndicator(
pagerState: PagerStateBridge,
pageCount: Int,
modifier: Modifier = Modifier,
pageIndexMapping: (Int) -> Int = { it },
activeColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
inactiveColor: Color = activeColor.copy(ContentAlpha.disabled),
indicatorWidth: Dp = 8.dp,
indicatorHeight: Dp = indicatorWidth,
spacing: Dp = indicatorWidth,
indicatorShape: Shape = CircleShape,
onIndicatorClick: (Int) -> Unit,
) {
val indicatorWidthPx = LocalDensity.current.run { indicatorWidth.roundToPx() }
val spacingPx = LocalDensity.current.run { spacing.roundToPx() }
Box(
modifier = modifier,
contentAlignment = Alignment.CenterStart
) {
Row(
horizontalArrangement = Arrangement.spacedBy(spacing),
verticalAlignment = Alignment.CenterVertically,
) {
repeat(pageCount) {
Box(
modifier = Modifier
.size(width = indicatorWidth, height = indicatorHeight)
.clip(indicatorShape)
.background(color = inactiveColor)
.clickable { onIndicatorClick(it) } //modified here
)
}
}
Box(
Modifier
.offset {
val position = pageIndexMapping(pagerState.currentPage)
val offset = pagerState.currentPageOffset
val next = pageIndexMapping(pagerState.currentPage + offset.sign.toInt())
val scrollPosition = ((next - position) * offset.absoluteValue + position)
.coerceIn(
0f,
(pageCount - 1)
.coerceAtLeast(0)
.toFloat()
)
IntOffset(
x = ((spacingPx + indicatorWidthPx) * scrollPosition).toInt(),
y = 0
)
}
.size(width = indicatorWidth, height = indicatorHeight)
.then(
if (pageCount > 0) Modifier.background(
color = activeColor,
shape = indicatorShape,
)
else Modifier
)
)
}
}
Also you have to add the PagerStateBridge
interface since it is internal.
internal interface PagerStateBridge {
val currentPage: Int
val currentPageOffset: Float
}
Upvotes: 2