Closed sebastinto closed 2 years ago
You can call animateScrollBy() on the PagerState, however you will need to manually calculate the amount of pixels to scroll, this is essentially a page size & amount of pages you want to scroll
You can call animateScrollBy() on the PagerState, however you will need to manually calculate the amount of pixels to scroll, this is essentially a page size & amount of pages you want to scroll
That works! Thanks for the quick reply!
Hi @sebastinto Can you share your code how you were able to achieve that?
@arifur-nureca I'm animating Card
components that auto-scroll forward then back to the start, in a loop so it looks something like this:
States
val pagerState = rememberPagerState()
var pageSize by remember { mutableStateOf(IntSize.Zero) }
val lastIndex by remember(pagerState.currentPage) {
derivedStateOf {pagerState.currentPage == items.size - 1 }
}
Scroll
LaunchedEffect(Unit) {
while (true) {
yield()
delay(6000)
pagerState.animateScrollBy(
value = if (lastIndex) -(pageSize.width.toFloat() * items.size) else pageSize.width.toFloat(),
animationSpec = tween(if (lastIndex) 2000 else 1400)
)
}
}
pageSize
is assigned with an onSizeChanged
Modifier
on the Card
HorizontalPager(
count = items.size,
state = pagerState
) { pageIndex ->
Card(modifier = modifier.onSizeChanged { pageSize = it } ) { /* card content */ }
}
@sebastinto i have and issue for your code, please could you solve this. i was follow your step and after swipe the pager, automatic pager didnt working, i put the scale in the box as my container.
@sebastinto i have and issue for your code, please could you solve this. i was follow your step and after swipe the pager, automatic pager didnt working, i put the scale in the box as my container.
Swiping doesn't break automatic paging with the code posted above so there must be something going on on your end. Please post your code. Or even better, post your question to StackOverflow because this is probably not the best place for troubleshooting. Feel free to link to this issue though.
@sebastinto
val items = DashboardSlider1.getData()
val pagerState = rememberPagerState()
var pageSize by remember { mutableStateOf(IntSize.Zero) }
val lastIndex by remember(pagerState.currentPage) {
derivedStateOf { pagerState.currentPage == items.size - 1 }
LaunchedEffect(Unit) {
while (true) {
yield()
delay(2000)
pagerState.animateScrollBy(
value = if (lastIndex) -(pageSize.width.toFloat() * items.size) else pageSize.width.toFloat(),
animationSpec = tween(if (lastIndex) 2000 else 1400)
)
}
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(12.dp)
.verticalScroll(rememberScrollState())
) {
TopSectionDashboard()
Spacer(modifier = Modifier.height(20.dp))
Box {
HorizontalPager(count = items.size, state = pagerState) { page ->
AutomaticSliderCard(item = items[page],Modifier.onSizeChanged { pageSize = it })
}
Indicators(
size = items.size,
index = pagerState.currentPage,
modifier = Modifier.align(Alignment.BottomCenter)
)
}
`
@Composable
fun AutomaticSliderCard(item: DashboardSlider1, modifier: Modifier = Modifier) {
Box(
modifier = modifier
.fillMaxWidth()
.height(200.dp)
) {
Image(
painter = painterResource(id = R.drawable.background_dashboard_slider1),
contentDescription = null,
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center,
contentScale = ContentScale.Crop,
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.align(Alignment.CenterStart)
.offset(y = -20.dp)
) {
Column(horizontalAlignment = Alignment.Start) {
Text(
text = item.title.toString(),
fontFamily = Poppins,
fontSize = 20.sp,
color = Color.White,
modifier = Modifier.padding(horizontal = 24.dp)
)
Text(
text = "${item.numberCount}",
fontFamily = Poppins,
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
color = Color.White,
modifier = Modifier
.padding(horizontal = 24.dp)
.offset(y = -10.dp)
)
}
Image(
painter = painterResource(id = item.image),
contentDescription = null,
modifier = Modifier.size(120.dp),
alignment = Alignment.CenterEnd
)
}
}
}
@imamyusupb
Yup I can certainly reproduce. Nice catch!
Try wrapping the LaunchedEffect
like this:
val isDragged by pagerState.interactionSource.collectIsDraggedAsState()
if (!isDragged) {
LaunchedEffect(Unit) {
while (true) {
yield()
delay(2000)
pagerState.animateScrollBy(
value = if (lastIndex) - (pageSize.width.toFloat() * items.size) else pageSize.width.toFloat(),
animationSpec = tween(if (lastIndex) 2000 else 1400)
)
}
}
}
More info on StackOverflow.
This seems to be a pretty solid fix from what I can tell. Let me know if that works you.
@sebastinto thanks, that's very kind of you
when addingcontentPadding
and pageSpacing
to the horizontal pager the scolling is messed up. any idea how to calculate the page size with those padding?
@SodaSurfer Pager
is now officially supported in androidx.compose.foundation.pager (more documentation here).
Playing with the new API for just a second, it seems like contentPadding
does NOT affect scrolling but pageSpacing
does.
First idea that came to mind was that you could do something like this as a workaround (although there may be a better way):
Declare a variable for your page spacing:
val pageSpacingDp = 16.dp
Calculate its equivalent in pixels inside your composable function:
val density = LocalDensity.current
val pageSpacingPx by remember {
with(density) {
mutableFloatStateOf(pageSpacingDp.toPx())
}
}
Provide pageSpacingDp
to the HorizontalPager
:
HorizontalPager(
count = items.size,
state = pagerState,
contentPadding = PaddingValues(horizontal = /* some dp value*/),
pageSpacing = pageSpacingDp,
) { pageIndex ->
Card(modifier = modifier.onSizeChanged { pageSize = it } ) { /* card content */ }
}
Then calculate the scroll animation this way:
pagerState.animateScrollBy(
value = if (lastIndex) (pageSize.width + pageSpacingPx) * -items.size else pageSize.width + pageSpacingPx,
animationSpec = tween(if (lastIndex) 2000 else 1600)
)
You can call animateScrollBy() on the PagerState, however you will need to manually calculate the amount of pixels to scroll, this is essentially a page size & amount of pages you want to scroll
@andkulikov Sorry, but this solution sucks and no one should have to do this. I need to navigate to several different pages backwards and forwards. Suggesting that we measure the number of pixels is like something out of 2012. Jetpack Compose should be better than this. The default animation is too fast, and you should be able to easily adjust it.
You can call animateScrollBy() on the PagerState, however you will need to manually calculate the amount of pixels to scroll, this is essentially a page size & amount of pages you want to scroll
@andkulikov Sorry, but this solution sucks and no one should have to do this. I need to navigate to several different pages backwards and forwards. Suggesting that we measure the number of pixels is like something out of 2012. Jetpack Compose should be better than this. The default animation is too fast, and you should be able to easily adjust it.
My comment was written two years ago. Since then the Pager from accompanist (this library) was deprecated as we introduced an official Pager right in the main compose:foundation library. The scroll function from there allows you to pass an animation spec
Since
animationSpec
was removed in v0.19.0 are we left with no control over animation duration when callinganimateScrollToPage()
? Is there a workaround to bring some amount of control back? Thanks!