I have the following screen:
fun ItemsScreen(
viewModel: ItemsViewModel = hiltViewModel()
) {
val showProgressBarState = remember { mutableStateOf(false) }
if (showProgressBarState.value) { ShowProgressBar() }
when(val resource = viewModel.state.value) {
is Loading -> ShowProgressBar() //Works perfectly
is Success -> LazyColumn {
items(
items = resource.data
) { item ->
ItemCard(
item = item
)
}
when(val r = viewModel.s.value) {
is Loading -> showProgressBarState.value = true
is Success -> showProgressBarState.value = false
is Failure -> Log.d(TAG, "Failure")
}
}
is Failure -> Text(
text = r.message,
modifier = Modifier.padding(16.dp)
)
}
}
@Composable
fun ShowProgressBar() {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}
The second "when" is for a delete state. I want when a item is deleted to start the progress bar. It starts but behind the LazyColumn. How to add it in front?
This is what I have in the activity class:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Scaffold(
//
) {
ItemsScreen()
}
}
}
CodePudding user response:
Wrap your all content into Box and also place your progressbar to top of your content.
Box(){
when(val resource = viewModel.state.value) {
is Success -> LazyColumn {
}
is Loading -> ShowProgressBar() //move to top layer
}
}
CodePudding user response:
You're updating your state value inside the view builder. It'll work in this case, but generally it's a bad practice which may lead to redundant recompositions which may slow your app. I'm talking about this part:
when(val r = viewModel.s.value) {
is Loading -> showProgressBarState.value = true
is Success -> showProgressBarState.value = false
is Failure -> Log.d(TAG, "Failure")
}
You should change state using side effects. Here you could've use LaunchedEffect
, so content would be called only when specified key is changed since the last recomposition.:
LaunchedEffect(viewModel.s.value) {
when (val r = viewModel.s.value) {
is Loading -> showProgressBarState.value = true
is Success -> showProgressBarState.value = false
is Failure -> Log.d(TAG, "Failure")
}
}
But actually that was an off topic for the future, in this case you don't need showProgressBarState
at all.
When you use Box
, items are displayed on the screen on on top of each other. As you need to display the progress bar on top of LazyColumn
, you need to wrap it with a Box
and place ShowProgressBar
after LazyColumn
.
Also you can specify contentAlignment = Alignment.Center
instead of wrapping CircularProgressIndicator
with a Column
:
is Resource.Success -> {
Box(contentAlignment = Alignment.Center) {
LazyColumn {
items(
items = resource.data
) { item ->
ItemCard(
item = item
)
}
}
when (val r = viewModel.s.value) {
is Resource.Loading -> CircularProgressIndicator()
is Resource.Success -> Unit
is Resource.Failure -> Log.d(TAG, "Failure")
}
}
}