Search code examples
androidkotlinandroid-jetpack-composejetpack-compose-modalbottomsheet

ModalBottomSheetLayout not opening again in jetpack compose


I was learning ModalBottomSheetLayout in my project. I have a Button and onClick I am sending Boolean to show sheetContent. It works once without any problem. After clicking on outside of ModalBottomSheetLayout it closes the sheetContent. After again clicking on `Button, sheet is not opening again. I don't understand what is the problem in here.

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    private val viewModel by viewModels<MainActivityViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        viewModel.enableBottomSheet.observe(this) {
            binding.bottomSheetComposeView.setContent {
                ModalBottomSheetSample(it)
            }
        }

        binding.buttonComposeView.setContent {
            ButtonView()
        }
    }

    @Composable
    fun ButtonView() {
        Column(Modifier.fillMaxSize()) {
            Button(onClick = {
                viewModel.enableBottomSheet.postValue(true)
            }) {
                Text(text = "Open Bottom Sheet")
            }
        }
    }

    @Composable
    @OptIn(ExperimentalMaterialApi::class)
    fun ModalBottomSheetSample(value: Boolean) {
        val state = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden, skipHalfExpanded = true)
        val scope = rememberCoroutineScope()
        SideEffect {
            scope.launch {
                if (value) {
                    state.show()
                }
            }
        }
        ModalBottomSheetLayout(
            sheetState = state,
            sheetContent = {
                LazyColumn {
                    items(5) {
                        ListItem(
                            icon = {
                                Icon(
                                    Icons.Default.Favorite,
                                    contentDescription = null
                                )
                            },
                            text = { Text("Item $it") },
                        )
                    }
                }
            }
        ) {}
    }

}

MainActivityViewModel.kt

class MainActivityViewModel : ViewModel() {
    val enableBottomSheet by lazy { MutableLiveData(false) }
}

Output

Here in this video, you can clearly see 1st time open the Bottom sheet on Button click. But not open for next click. Thanks

I am using compose_bom = "2023.03.00". Please don't suggested alpha or beta fix.


Solution

  • I changes two things.

    1. Change State of function i.e. StateFul and StateLess separate function.
    2. Change from LiveData to MutableSharedFlow and it working fine.

    MainActivityViewModel.kt

    class MainActivityViewModel : ViewModel() {
        val showBottomSheetContent by lazy { MutableSharedFlow<Boolean>() }
    }
    

    MainActivity.kt

    class MainActivity : AppCompatActivity(), HideViewListener {
    
        private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
        private val viewModel by viewModels<MainActivityViewModel>()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(binding.root)
            lifecycleScope.launch {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    viewModel.showBottomSheetContent
                        .collect { value ->
                            binding.bottomSheetComposeView.setContent {
                                ModalBottomSheetSample(value)
                            }
                        }
                }
            }
    
            binding.buttonComposeView.setContent {
                ButtonViewContent()
            }
        }
    
        @Composable
        fun ButtonViewContent() {
            val scope = rememberCoroutineScope()
            Column(Modifier.fillMaxSize()) {
                Button(
                    onClick = {
                        scope.launch {
                            viewModel.showBottomSheetContent.emit(true)
                        }
                    }
                ) {
                    Text(text = "Open Bottom Sheet")
                }
            }
        }
    
        @Composable
        @OptIn(ExperimentalMaterialApi::class)
        fun ModalBottomSheetSample(value: Boolean) {
            val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden, skipHalfExpanded = true)
            val scope = rememberCoroutineScope()
            SideEffect {
                scope.launch {
                    if (value) {
                        sheetState.show()
                    }
                }
            }
            ModalBottomSheetContent(sheetState)
        }
    
        @OptIn(ExperimentalMaterialApi::class)
        @Composable
        fun ModalBottomSheetContent(sheetState: ModalBottomSheetState) {
            ModalBottomSheetLayout(
                sheetState = sheetState,
                sheetContent = {
                    LazyColumn {
                        items(5) {
                            ListItem(
                                icon = {
                                    Icon(
                                        Icons.Default.Favorite,
                                        contentDescription = null
                                    )
                                },
                                text = { Text("Item $it") },
                            )
                        }
                    }
                }
            ) {}
        }
    
    }