Marat
Marat

Reputation: 1358

How to add swipe behavior to the screens?

We have bottom navigation in our app and we want to add swipe behavior into our screens so that if a user swipe to right/left then s/he should be navigated into next screen.

I know that Accompanist has HorizontalPager with Tabs. But I wonder if we can achieve that behavior with bottom navigation.

Upvotes: 11

Views: 8531

Answers (2)

Raul Lucaciu
Raul Lucaciu

Reputation: 162

you can achieve this by using the animation library from compose: https://developer.android.com/jetpack/compose/animation

And using the slideIntoContainer animation you can simulate the swipe effect:

 composable("route1",
        enterTransition = {
            slideIntoContainer(
                towards = AnimatedContentScope.SlideDirection.Right,
                animationSpec = tween(
                    durationMillis = 250,
                    easing = LinearEasing // interpolator
                )
            )
        },
        exitTransition = {
            slideOutOfContainer(
                towards = AnimatedContentScope.SlideDirection.Left,
                animationSpec = tween(
                    durationMillis = 250,
                    easing = LinearEasing
                )
            )
        }) {
        Screen1()
    }
    composable("route2",
        enterTransition = {
            slideIntoContainer(
                towards = AnimatedContentScope.SlideDirection.Left,
                animationSpec = tween(
                    durationMillis = 250,
                    easing = LinearEasing // interpolator
                )
            )
        },
        exitTransition = {
            slideOutOfContainer(
                towards = AnimatedContentScope.SlideDirection.Right,
                animationSpec = tween(
                    durationMillis = 250,
                    easing = LinearEasing
                )
            )
        }) {
        Screen2()
    }

Upvotes: 4

nglauber
nglauber

Reputation: 24044

As you can see in the Material Design Guidelines:

Using swipe gestures on the content area does not navigate between views.

Also:

Avoid using lateral motion to transition between views.

But, if you really want to do this, you can do the this:

fun BottomNavSwipeScreen() {
    // This scope is necessary to change the tab using animation
    val scope = rememberCoroutineScope()
    // I'm using a list of images here
    val images = listOf(R.drawable.img1, ...) 
    // This page state will be used by BottomAppbar and HorizontalPager
    val pageState = rememberPagerState(pageCount = images.size)
    val scaffoldState = rememberScaffoldState() 
    Scaffold(
        scaffoldState = scaffoldState,
        bottomBar = {
            BottomAppBar(
                backgroundColor = MaterialTheme.colors.primary,
                content = {
                    for (page in images.indices) {
                        BottomNavigationItem(
                            icon = { 
                                Icon(Icons.Filled.Home, "Page $page") 
                            },
                            // here's the trick. the selected tab is based
                            // on HorizontalPager state.
                            selected = page == pageState.currentPage,
                            onClick = {
                                // When a tab is selected, 
                                // the page is updated
                                scope.launch {
                                    pageState.animateScrollToPage(page)
                                }
                            },
                            selectedContentColor = Color.Magenta,
                            unselectedContentColor = Color.LightGray,
                            label = { Text(text = "Page $page") }
                        )
                    }
                }
            )
        },
    ) {
        HorizontalPager(
            state = pageState,
            offscreenLimit = 2
        ) { page ->
            Image(
                painterResource(id = images[page]),
                null,
                modifier = Modifier
                    .fillMaxSize(),
                contentScale = ContentScale.Crop
            )
        }
    }
}

Here is the result:

enter image description here

Upvotes: 9

Related Questions