Reputation: 2338
Is there a manual way or an appropriate way to change the current page for a Pager?
I may be breaking some written rules, but essentially I am updating the content of pages, but not changing the number of pages.
The original list might be
A
B
C
D
… (repeat ABCD forever until you cap at Int.MAX_VALUE)
And the next minute it might be
A
B
C
D
E
F
… (same repeat)
I have accurately figured out how to calculate where I want to be in each pager if the number of values changes for any reason, but nothing I’ve done changes the value.
val pageCount = Int.MAX_VALUE
val halfSet = (pageCount / 2)
val offset = halfSet % items.size
val initial = halfSet - offset
val initialPage = initial + selected - (initial % items.size) - 1 // This changes
val pageState = rememberPagerState(
initialPage = initialPage // This never updates
)
LaunchedEffect(
key1 = pageState,
key2 = initialPage // this is also constant
) {
snapshotFlow { pageState.currentPage }.collect { page ->
// Center page is a little strange... So. +1...
// This definitely breaks or gets weird near the edges.
//val actualPage = (if(intitalPage != page) intitalPage else page) + 1 // forever returns the first value that intialPage equaled
val actualPage = page + 1
actualSelected = actualPage % items.size
onChange(actualSelected)
Log.d(TAG, "$actualPage ${items[actualSelected]} ")
}
}
The actualSelected
technically is correct now because it does return the value that the page is currently on. I’ve stumbled into that working out. But if A
was the selected value and the size of the list changes D
might become selected and I really want A
to stay. The initalPage
is correctly returning to me the position I want it to be, but nothing I’m doing fixes it. And technically scrolling to it causes a ton of recompositions I don’t want. I just want it to “jump” or be at the right page I tell it to be.
Upvotes: 2
Views: 4250
Reputation: 2818
Thank you for posting. It helped me a lot in solving the same Bug. But I think your calculations are a bit more complex than they need to be. This solution also works:
@Composable
fun InfiniteHorizontalPager(
pageCount: Int,
modifier: Modifier = Modifier,
initialPage: Int = 0,
onPageChanged: ((index: Int) -> Unit)? = null,
content: @Composable PagerScope.(page: Int) -> Unit,
) {
val max = Short.MAX_VALUE.toInt()
val half = max / 2
val pagerPositionIndex = initialPage + half - half % pageCount
val pagerState = rememberPagerState(pageCount = { max }, initialPage = pagerPositionIndex)
LaunchedEffect(pagerPositionIndex, pageCount) {
pagerState.scrollToPage(pagerPositionIndex)
}
if (onPageChanged != null) {
LaunchedEffect(pagerState, pageCount) {
snapshotFlow { pagerState.currentPage }.collect { index ->
onPageChanged(index % pageCount)
}
}
}
HorizontalPager(
state = pagerState,
userScrollEnabled = pageCount > 1,
modifier = modifier,
) { index ->
content(index % pageCount)
}
}
Upvotes: 1
Reputation: 2338
Figured it out…
val pageCount = Int.MAX_VALUE
val halfSet = (pageCount / 2)
val offset = halfSet % items.size
val initial = halfSet - offset
val target = initial + selected - (initial % items.size) - 1
val pageState = rememberPagerState(
initialPage = target
)
LaunchedEffect(
key1 = items
) {
pageState.scrollToPage(target)
}
LaunchedEffect(
key1 = pageState,
key2 = items
) {
snapshotFlow { pageState.currentPage }.collect { page ->
// Center page is a little strange... So. +1...
// This definitely breaks or gets weird near the edges.
val actualPage = page + 1
actualSelected = actualPage % items.size
onChange(actualSelected)
if(debug) Log.d(TAG, "$actualPage ${items[actualSelected]} ")
}
}
So essentially you have to use 2 LaunchedEffect
listeners. I don’t know exactly why as I tried to do the scrollToPage(Int)
in the second one before and it didn’t work. If anyone has details on that that would be beneficial I think.
However, this works very well.
Upvotes: 1