Search code examples
android-jetpack-composeprogress-bar

Show a progress bar during a new screen navigation in Compose


In stackoverflow I can find many examples on how to show progress bar inside the screen while running a process in the screen but I don't find an example on showing one between screens.

I have some screens that takes maybe a minute to show when is called. I wish to give the users some feedback while they wait for the new screen to fully show.


Solution

  • I found a partial but very close solution to this problem.

    I made a Progress bar Composable that calls a function and that function is the one that calls the new screen. Make sure the New Screen is main-safe so the progress bar animation runs smoothly.

    It is still not complete because even though it works the progress animation still stops during final transition, it seems the two screens compete for the Main thread instead of sharing. I have not found a way to make the Composables in the New Screen to run in a lower priority than the Progress Bar.

    This is the Progress Bar Composable:

    @Composable
    fun Progressbar(show: MutableState<Boolean>, myfun: ()->Unit ) {
    
    if (show.value) {
        Dialog(
            onDismissRequest = { show.value = false },
            DialogProperties(
                dismissOnBackPress = false,
                dismissOnClickOutside = false,
                usePlatformDefaultWidth = false,
                decorFitsSystemWindows = false
            )
        ) {
    
    
            val scope = rememberCoroutineScope()
            var firstL by remember { mutableStateOf(true) }
            var end by remember { mutableStateOf(false) }
            Box(
                contentAlignment = Alignment.Center,
                modifier = Modifier
                    .fillMaxSize()
                    .background(White, shape = RoundedCornerShape(8.dp)) 
            ) {
                Text(text = "Loading, please wait.", fontSize = 20.sp, fontWeight = FontWeight.Bold)
    
                CircularProgressIndicator(
                    // below line is use to add padding
                    // to our progress bar.
                    modifier = Modifier
                        .size(200.dp)
                        .padding(16.dp),
    
                    // below line is use to add color
                    // to our progress bar.
                    color = colorResource(id = R.color.purple_200),
    
                    // below line is use to add stroke
                    // width to our progress bar.
                    strokeWidth = Dp(value = 4F)
                )
    
                if (firstL) {
                    firstL = false
                    LaunchedEffect(Unit) {
                        val res = scope.launch {
                            delay(1000)
                            myfun()
                        }
                        res.join() //Here we set the progress bar to wait for the myfun to finish
                        end = true //When finished set flag
                    }
                }
    
                if (end) { //When flag is true self turn off Progress bar
                    show.value = false
                }
            }
        }
    }
    }
    

    Then to use the Composable to call the new screen:

    val showDialog = remember { mutableStateOf(false) }
    
    Button(
           onClick = {
                        showDialog.value = true
                        //navController.navigate("NewScreen") Instead of calling screen here.
                    },
                    colors = ButtonDefaults.buttonColors(Color.Blue)
    
                ) {
                    Text(text = stringResource(R.string.newscreen))
                }
    
    //Call screen inside the Progress Bar
    Progressbar(show = showDialog) { navController.navigate("NewScreen") }