Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HorizontalPager scrolling bug. #1069

Closed
ijero opened this issue Mar 7, 2022 · 7 comments
Closed

HorizontalPager scrolling bug. #1069

ijero opened this issue Mar 7, 2022 · 7 comments
Assignees

Comments

@ijero
Copy link

ijero commented Mar 7, 2022

Describe the bug

Calling pagerState.animateScrollToPage() always doesn't scroll to the full next page, it happens in v0.24.3-alpha version.

When I try to downgrade to v0.24.2-alpha it works fine.

To Reproduce

Steps to reproduce the behavior:

  1. Import 0.24.3-alpha:
def accompanist = "0.24.3-alpha"
implementation "com.google.accompanist:accompanist-pager:$accompanist"
  1. Use code:
    val pagerState = rememberPagerState()
    LaunchedEffect(key1 = pagerState.currentPage) {
        logd(
            "LaunchedEffect",
            "pageCount=${pagerState.pageCount}, currentPage=${pagerState.currentPage}"
        )
        delay(2000)
        logd(
            "LaunchedEffect",
            "scroll to ${pagerState.currentPage.inc() % pagerState.pageCount} page."
        )
        pagerState.animateScrollToPage(pagerState.currentPage.inc() % pagerState.pageCount)
    }
    HorizontalPager(
        modifier = Modifier
            .fillMaxWidth()
            .aspectRatio(1961 / 862f),
        count = bannerState.value.size,
        state = pagerState,
    ){
    // ...
   }
  1. Log print:
 D/LaunchedEffect: pageCount=0, currentPage=0
 D/LaunchedEffect: scroll to 1 page.
 D/LaunchedEffect: pageCount=4, currentPage=1
 D/LaunchedEffect: scroll to 2 page.
 D/LaunchedEffect: pageCount=4, currentPage=2
 D/LaunchedEffect: scroll to 3 page.
 D/LaunchedEffect: pageCount=4, currentPage=3
 D/LaunchedEffect: scroll to 0 page.
 D/LaunchedEffect: pageCount=4, currentPage=2

Expected behavior

image

Screenshots?

image

image

Environment:

  • Android OS version: Android 10.0
  • Device: Emulator, Google Pixel 2 XL
  • Accompanist version: v0.24.3-alpha

Additional context

Add any other context about the problem here.

@andkulikov andkulikov self-assigned this Mar 8, 2022
@andkulikov
Copy link
Collaborator

Can you please help me understand why you write
LaunchedEffect(key1 = pagerState.currentPage)
Why do you want to re-start the scrolling everytime current page changes?
I think what happens is that now pagerState.currentPage changes in the middle of the scrolling and it cancels the previous scrolling coroutine.
do you just need an infinite automatic scroller?
maybe something like

    LaunchedEffect(key1 = pagerState) {
        while(true) {
              delay(2000)
              pagerState.animateScrollToPage(pagerState.currentPage.inc() % pagerState.pageCount)
        }
    }

will be more appropriate

@ijero
Copy link
Author

ijero commented Mar 8, 2022

Can you please help me understand why you write LaunchedEffect(key1 = pagerState.currentPage) Why do you want to re-start the scrolling everytime current page changes? I think what happens is that now pagerState.currentPage changes in the middle of the scrolling and it cancels the previous scrolling coroutine. do you just need an infinite automatic scroller? maybe something like

    LaunchedEffect(key1 = pagerState) {
        while(true) {
              delay(2000)
              pagerState.animateScrollToPage(pagerState.currentPage.inc() % pagerState.pageCount)
        }
    }

will be more appropriate

Thanks for your reply, I tried to use while(true) in LaunchedEffect, but when I actively swipe the Pager, the code in LaunchedEffect doesn't execute anymore, is there any other solution?

@andkulikov
Copy link
Collaborator

Could you please explain your requirements? So user can scroll manually with a finger, but the user initiated scrolling is finished you want to start automatically scrolling with 2000 delay?

@ijero
Copy link
Author

ijero commented Mar 8, 2022

Could you please explain your requirements? So user can scroll manually with a finger, but the user initiated scrolling is finished you want to start automatically scrolling with 2000 delay?

Yes this is what i want.

@andkulikov
Copy link
Collaborator

Try this one

            val isDraggedState = pagerState.interactionSource.collectIsDraggedAsState()
            LaunchedEffect(isDraggedState) {
                snapshotFlow { isDraggedState.value }
                    .collectLatest { isDragged ->
                        if (!isDragged) {
                            while (true) {
                                delay(2000)
                                try {
                                    pagerState.animateScrollToPage(pagerState.currentPage + 1)
                                } catch (ignore: CancellationException) {
                                }
                            }
                        }
                    }
            }

@ijero
Copy link
Author

ijero commented Mar 8, 2022

Try this one

            val isDraggedState = pagerState.interactionSource.collectIsDraggedAsState()
            LaunchedEffect(isDraggedState) {
                snapshotFlow { isDraggedState.value }
                    .collectLatest { isDragged ->
                        if (!isDragged) {
                            while (true) {
                                delay(2000)
                                try {
                                    pagerState.animateScrollToPage(pagerState.currentPage + 1)
                                } catch (ignore: CancellationException) {
                                }
                            }
                        }
                    }
            }

Thank you very much, it works as I expected

@surensth
Copy link

surensth commented Dec 12, 2023

Thanks for above solution. If incase anyone need to go to initial page, then this might help.

val isDraggedState = pagerState.interactionSource.collectIsDraggedAsState()
   LaunchedEffect(isDraggedState) {
       snapshotFlow { isDraggedState.value }
           .collectLatest { isDragged ->
               if (!isDragged) {
                   while (true) {
                       delay(2000)
                       try {
                           pagerState.animateScrollToPage(pagerState.currentPage + 1)
                           //If anyone need to go to initial page after last page
                           if (pagerState.currentPage == pagerState.pageCount - 1)
                               pagerState.animateScrollToPage(pagerState.initialPage)
                       } catch (ignore: CancellationException) {
                       }
                   }
               }
           }
   }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants