Ahmed Maher
Ahmed Maher

Reputation: 21

Bottom navigation bar appears above modal bottom sheet in jetpack compose

I have post in this post I have icon for comments when the user click on it, it should open modal bottom sheet but the problem is Bottom navigation bar appears above modal bottom sheet in jetpack compose, I want to hide the bottom navigation when modal bottom sheet is opening, I will explain this in pictures below post modal bottom sheet

this code is for the screen that have bottom navigation bar :

@Composable
fun HomeScreenWidget(homeViewModel: HomeViewModel = hiltViewModel()) {
    val systemUiController = rememberSystemUiController()
    systemUiController.setSystemBarsColor(
        color = BackgroundColor
    )
    LaunchedEffect(true) {
        homeViewModel.getCurrentUser()
    }
    val getCurrentUserResult by homeViewModel.getCurrentUserResult.collectAsState()
    if (getCurrentUserResult is Resource.Loading) {
        CircularProgressIndicator()
    } else {
        when (getCurrentUserResult) {
            is Resource.Success -> {
                currentUser = getCurrentUserResult.data
            }
            is Resource.Error -> {
                Timber.e(getCurrentUserResult.message)
            }
            else -> {}
        }
    }

    val navController = rememberNavController()
    Scaffold(
        floatingActionButton = {
            IconButton(
                interactionSource = NoRippleInteractionSource(),
                modifier = Modifier
                    .background(FabColor, shape = CircleShape)
                    .size(65.dp),
                onClick = {},
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.insta_ic),
                    contentDescription = "Add",
                    tint = Color.White
                )
            }
        },
        isFloatingActionButtonDocked = true,
        floatingActionButtonPosition = FabPosition.Center,
        bottomBar = {
            BottomNavigationView(navController)
        },
        content = {
            Modifier.padding(it)
            DestinationsNavHost(
                navController = navController,
                navGraph = NavGraphs.root,
                startRoute = FeedScreenDestination
            )
        }
    )
}

this code is for feeds screen that have posts and modal bottom sheet :

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun FeedScreenWidget(
    homeViewModel: HomeViewModel = hiltViewModel(),
    navigator: DestinationsNavigator
) {
    val systemUiController = rememberSystemUiController()
    systemUiController.setSystemBarsColor(
        color = BackgroundColor
    )
    val lazyPagingItems = homeViewModel.followingPostsListPager.collectAsLazyPagingItems()
    val lazyColumnState = rememberLazyListState()

    var searchText by remember {
        mutableStateOf("")
    }
    val usernameForModalSheet = remember { mutableStateOf("") }
    val postIdForModalSheet = remember { mutableStateOf("") }
    val isCommentClicked = remember { mutableStateOf(false) }
    val modalBottomSheetState =
        rememberModalBottomSheetState(
            initialValue = ModalBottomSheetValue.Hidden,
            skipHalfExpanded = true
        )
    val scope = rememberCoroutineScope()
    ModalBottomSheetLayout(
        sheetContent = {
            ModalBottomSheetContent(
                navigator,
                usernameForModalSheet,
                postIdForModalSheet,
                homeViewModel,
                isCommentClicked
            )
        },
        modifier = Modifier.fillMaxSize(),
        sheetBackgroundColor = BackgroundColor,
        sheetState = modalBottomSheetState
    ) {
        Scaffold(
            content = {
                Modifier.padding(it)
                Column(
                    modifier = Modifier
                        .background(BackgroundColor)
                        .padding(15.dp)
                        .fillMaxSize()
                ) {
                    Column(
                        modifier = Modifier
                            .background(BackgroundColor)
                            .fillMaxSize()
                    ) {
                        ToolBar(modifier = Modifier)
                        Spacer(modifier = Modifier.height(10.dp))
//                        StorySection(modifier = Modifier, currentUser)
                        Spacer(modifier = Modifier.height(15.dp))
                        ExplorerSection(
                            modifier = Modifier,
                            value = searchText
                        ) { searchText = it }
                        Spacer(modifier = Modifier.height(10.dp))
                        PostsSection(
                            modifier = Modifier,
                            homeViewModel,
                            modalBottomSheetState,
                            scope,
                            usernameForModalSheet,
                            postIdForModalSheet,
                            isCommentClicked,
                            navigator,
                            lazyPagingItems,
                            lazyColumnState
                        )
                    }
                }

            }
        )
    }
}

Upvotes: 1

Views: 4487

Answers (1)

tasjapr
tasjapr

Reputation: 1240

This is not due to a bug in your code, but due to a bad component queue.

I also ran into this problem and after trying a lot of ideas, I came to the conclusion that the only possible way to achieve a good display in such a case is to change the order of function.

You need to move ModalBottomSheetLayout from screens that contain a navigation bar to a root function to get such structure:

@Composable
fun HomeScreenWidget(homeViewModel: HomeViewModel = hiltViewModel()) {
    Scaffold(){}
    ModalBottomSheetLayout()
}

To achieve this you need to pass data to the ModalBottomSheetLayout and also show it with some global state object. For example, you can create a variable in this global state object that will store the currently opened ModalBottomSheetLayout state and show or hide it this way.

For example:

In AppState class:

var openedPopup by mutableStateOf<OpenedPopup?>(null)
        private set

fun updateOpenedPopup(popup: OpenedPopup?) { // pass null to hide popup
        openedPopup = popup
}

OpenedPopup:

sealed class OpenedPopup {
    object SimplePopup : OpenedPopup() // no external data
    class ComplicatedPopup(val state: YourPopupDataState) : OpenedPopup()
}

In HomeScreenWidget:

val simpleBSS = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden, skipHalfExpanded = true)
val complBSS = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden, skipHalfExpanded = true)

LaunchedEffect(key1 = state.openedPopup) {
        when (state.openedPopup) {
            null -> {
                simpleBSS.hide()
                complBSS.hide()
            }
            SimplePopup -> simpleBSS.show()
            ComplicatedPopup -> complBSS.show()
        }
}

LaunchedEffect(Unit) {
        snapshotFlow { simpleBSS.currentValue }
            .collect { if (it == ModalBottomSheetValue.Hidden) state.updateOpenedPopup(null) }
    }

LaunchedEffect(Unit) {
        snapshotFlow { complBSS.currentValue }
            .collect { if (it == ModalBottomSheetValue.Hidden) state.updateOpenedPopup(null) }
    }

// place your ModalBottomSheetLayout here and pass state
// it is better to put each popup into a separate file and function
ModalBottomSheetLayout(sheetState = simpleBSS){}
ModalBottomSheetLayout(sheetState = complBSS){}

With this approach you can now call specific ModalBottomSheetLayout from anywhere like this:

state.updateOpenedPopup(SimplePopup)
state.updateOpenedPopup(ComplicatedPopup(YourPopupDataState()))

Note that this approach is only needed for screens where you have a navigation panel, if it doesn't then you can use the approach you have now.

Hope this helps

Upvotes: 0

Related Questions