Gianluca Veschi
Gianluca Veschi

Reputation: 1618

Bottom Nav Bar overlaps screen content in Jetpack Compose

I have a BottomNavBar which is called inside the bottomBar of a Scaffold.
Every screen contains a LazyColumn which displays a bunch of images.
For some reason when I finish scrolling, the BottomNavBar overlaps the lower part of the items list.
How can I fix this?

enter image description here

Here the set content of MainActivity

SetContent{
    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text(text = "tartufozon") },
                actions = {
                    IconButton(onClick = { Timber.d("Mail clicked") }) {
                        Icon(Icons.Default.Email, contentDescription = null)
                    }
                }
            )
        },
        bottomBar = {
            BottomNavBar(navController = navController)
        }
    ) {
    BottomNavScreensController(navController = navController)
    }
}

Upvotes: 96

Views: 32457

Answers (7)

Canturk Karabulut
Canturk Karabulut

Reputation: 136

The problem is solved by opening a Box there and giving the paddingValues value I wrote in it.

Scaffold(
            bottomBar = {
                BottomBar(navController = navController, bottomBarState = bottomBarState)
            },
            content = {paddingValues->
                Box(modifier = Modifier.padding(paddingValues)){
                    SetupNavGraph(navHostController = navController)
                }
            })
    }

Upvotes: 3

RobertoAllende
RobertoAllende

Reputation: 9548

Following ianhanniballake's answer and its comments and just to save you few minutes. The code would be something like:

Scaffold(
    topBar = {
      //
    },
    bottomBar = {
        //
    }
    ) { innerPadding ->
        Box(modifier = Modifier.padding(
          PaddingValues(bottom = innerPadding.calculateBottomPadding()) {
            BottomNavScreensController(navController = navController)
        }
    }
}

Upvotes: 17

Yehezkiel L
Yehezkiel L

Reputation: 441

Following ianhanniballake answer, if you have a list in your main screen and want to show/hide the bottom bar. It will perform unexpected behavior when you back to list screen (the scroll state is in very bottom) and show the navigation bar.The list item will scroll up a bit which cause the list doesn't fully scrolled to the bottom.

This is because of when you back to the list screen and want to show the bottom bar, the list already there. Then the bottom bar will show and list will not calculate the innerPadding for more.

enter image description here

To handle this, just pass the innerPadding into the list screen like this:

            Scaffold(
                bottomBar = {
                BottomNavBar(navController)
            }) { innerPadding ->
            NavHost(
                navController = navController,
                startDestination = MovieListDirections.destination
            ) {
                MovieListDirections.screenWithPaddingBottomBar(
                    this,
                    innerPadding.calculateBottomPadding() // pass here
                )
            }

Then in the list screen

@Composable
fun MovieListMainView(viewModel: MovieListViewModel = hiltViewModel(),
                  bottomBarHeight: Float) {
    val movieList by viewModel.movieList.collectAsState()
    var navBarHeight by rememberSaveable { mutableStateOf(0f) }

    if (bottomBarHeight != 0f) {
        navBarHeight = bottomBarHeight
    }

    MovieListLayout().MovieGridLayout(
        modifier = Modifier.padding(0.dp, 0.dp, 0.dp, navBarHeight.dp),
        movies = movieList.movieList.movieItems,
        onItemClick = {
            viewModel.onMovieClicked(it)
        })
}

Upvotes: -1

Tushar Ahmed
Tushar Ahmed

Reputation: 151

Add your layouts and views in content with its padding like in the example:

Scaffold(
        content = {
            Box(modifier = Modifier.padding(it)) {
                //add your layout here
            }

        },
        topBar = { 
                 //your top bar
        },
        floatingActionButton = {
           //your floating action bar
        },
        bottomBar = {
            //your bottom navigation
        }
    )

Upvotes: 2

Joel Kanyi
Joel Kanyi

Reputation: 511

Scaffold(
    bottomBar = {
       BottomNavigationBar(navController = navController)
   }
) { innerPadding ->
      Box(modifier = Modifier.padding(innerPadding)) {
               DestinationsNavHost(
                  navGraph = NavGraphs.root,
                  navController = navController,
                  engine = navHostEngine
                )
         }
}

Upvotes: 8

dessalines
dessalines

Reputation: 7382

You no longer need to do any calculations. In the scaffold content, do:

content = { padding ->
  Column(
    modifier = Modifier.padding(padding)
  ) {...

Upvotes: 10

ianhanniballake
ianhanniballake

Reputation: 200080

As per the API definition for Scaffold, your inner content (the trailing lambda you have your BottomNavScreensController in), is given a PaddingValues object that gives you the right amount of padding for your top app bar, bottom bar, etc.

Right now, you're not referencing that padding at all and hence, your content is not padded in. This is what is causing your overlap.

You can add a Box around your BottomNavScreensController to apply the padding, or pass the padding directly into your BottomNavScreensController so that each individual screen can correctly apply the padding; either solution works.

Scaffold(
    topBar = {
      //
    },
    bottomBar = {
        //
    }
    ) { innerPadding ->
        // Apply the padding globally to the whole BottomNavScreensController
        Box(modifier = Modifier.padding(innerPadding)) {
            BottomNavScreensController(navController = navController)
        }
    }
}

Upvotes: 178

Related Questions