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

Trouble swiping to other pages in pager after navigating within one page #1181

Closed
mchowning opened this issue Apr 6, 2023 · 5 comments
Closed
Assignees

Comments

@mchowning
Copy link

I'm having trouble building a wear app that allows navigation within one of the pages in a PagerScreen. I'm finding that once I navigate "inside" one of the pages, I can no longer swipe to switch pages.

For example, imagine an app with a PagerScreen that has two pages. The first page is a WearNavScaffold composable that starts on "Page 1". "Page 1" contains a button that navigates to a "subpage" composable. The second page in the PagerScreen is a basic composable that I'll call "Page 2".

When opening the app, I can use the pager to swipe from "Page 1" to "Page 2". If I tap on the button on "Page 1" to navigate to "subpage" however, I can no longer swipe to "Page 2" in the "PagerScreen" even though I am still opening within the "PagerScreen". Only once I swipe back to return to "Page 1" does the PagerScreen allow me to swipe to "Page 2" again.

Here is simplified pseudo-code of the composable setup I'm trying to describe:

PagerScreen(2) { page ->
    when (page) {
        0 -> {
            WearNavScaffold(startDestination = "start", ...) {
                composable("start") {
                        Column(...) {
                            Text("Page 1")
                            Button( onClick = { navController.navigate("subpage") }) {
                                Text("Navigate to subpage")
                            }
                        }
                    }
                }

                composable("subpage") {
                    Text("Subpage")
                }
            }
        }

        1 -> Text("Page 2")
    }
}

Here is a video showing how I am unable to switch to "Page 2" from the "subpage":

device-2023-04-05-21551.webm

I get the same behavior if I use a HorizontalPager instead of a PagerScreen and if I use a SwipeDismissibleNavHost instead of a WearNavScaffold. If, however, I build a phone app using a HorizontalPager and a NavHost, I am able to swipe between the pages even when I am on the "subpage" like I want.

Video of phone app with desired behavior
device-2023-04-05-221335.mp4

I have created a simple example project demonstrating the issue. The wear module shows the behavior I don't want (first video above), and the app module shows a phone app with the behavior I'm trying to achieve on wear.

Thanks so much for your help! 🙇

@kul3r4 kul3r4 self-assigned this Apr 11, 2023
@yschimke
Copy link
Collaborator

I suspect with some workarounds and careful config, you can make this work.

But in general I'd say that pushing navigation down into a pager is non-typical and problematic. In general a Pager is a type of LazyList, you effectively end up with 0..n instances of the NavHost. In your case n is 1, but it still means that there is no guarantee the nav host is created initially in the app. So it's hard to reason about things like deeplinks being processed. Or if you navigate to the second page and come back, the user may lose screen state.

I'd strongly suggest putting the nav host (which WearNavScaffold wraps) at the top level of your app, and a pager screen inside that.

@mchowning
Copy link
Author

mchowning commented Apr 25, 2023

I'd strongly suggest putting the nav host (which WearNavScaffold wraps) at the top level of your app, and a pager screen inside that.

Thanks for your feedback. 🙇

I've gone forward with that approach. One challenge I'm seeing comes from the fact that the pages within my pager are now operating within the same navigation context. For example, if the first page is scrollable and hides the time text (by scrolling down), then the time text won't appear on any of the other pages.

This gets even a bit trickier when both the pages in the pager are scrollable. In that case, it doesn't seem like I can fully use the horologist scrollable components on both pages because I only have access to a single ScrollableScaffoldContext (since they're both within the same navigation destination now). Passing the ScalingLazyListState provided the ScrollableScaffoldContext context to both the scrollable components results in scroll on one page affecting the scroll position on the other page.

I've worked around this by just using the ScalingLazyColumn from foundation for the second scrollable page and hiding the TimeText when the pager is on that page, which works well enough, so I'm not blocked. This does mean that I only have the option to scroll away the TimeText on a single page in the pager. Having more than one scrollable pager probably isn't the typical use case, but it doesn't feel that unusual either.

@yschimke
Copy link
Collaborator

Yep, missing functionality #823

I'll see if we can implement.

@yschimke
Copy link
Collaborator

No plans to fix in Horologist

@yschimke
Copy link
Collaborator

With low certainty possible fixed or minimised by this PR #1866

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