1

I am trying to create a Composable that wraps another content Composable and displays a CircularProgressBar as an overlay on top of it, covering the whole content Composable.

I almost got it working as wished, see the following to images:

Initial state

Initial state

Loading state

Loading state

But as you can see, the overlay fills the complete screen instead of just the gray LazyRow item and the text field. Thus, the button is pushed off screen.

This is my current code:

@Composable
fun LoadingBox(
    modifier: Modifier = Modifier,
    isLoading: Boolean = false,
    loadingText: String,
    content: @Composable() () -> Unit
) {
    Box(modifier = modifier
        .fillMaxWidth()
        .wrapContentHeight()
    ) {

        content()
        if (isLoading) {

            Surface(
                modifier = Modifier
                    .fillMaxSize()
                    .alpha(0.5f),
            ) {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    verticalArrangement = Arrangement.Center,
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    CircularProgressIndicator()
                    Text(text = loadingText)
                }
            }
        }
    }
}

On the screenshots, I am providing the gray box and the text field as the content parameter. So the overlay should only cover the gray LazyRow item and the text field.

I already stumbled across instrinsic measures, however I cannot use them as the App crashes when I provide a LazyRow as content due to following error:

java.lang.IllegalStateException: Asking for intrinsic measurements of SubcomposeLayout layouts is not supported. This includes components that are built on top of SubcomposeLayout, such as lazy lists, BoxWithConstraints, TabRow, etc. To mitigate this:
- if intrinsic measurements are used to achieve 'match parent' sizing,, consider replacing the parent of the component with a custom layout which controls the order in which children are measured, making intrinsic measurement not needed
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
BenjyTec
  • 1,719
  • 2
  • 12
  • 22

1 Answers1

3

You should:

  • add contentAlignment = Alignment.Center in the parent Box
  • Remove the Surface
  • remove the verticalArrangement in the Column
  • Add an other Box which you can fill with a translucent background

Something like:

Box(modifier = modifier
    .fillMaxWidth(),
    contentAlignment = Alignment.Center,
) {

    content()
    if (isLoading) {
        Box(
            Modifier
                .matchParentSize()
                .background(Color.Gray.copy(alpha = 0.5f))

        )

        Column(
            modifier = Modifier.fillMaxWidth(),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            androidx.compose.material.CircularProgressIndicator()
            Text(text = loadingText)
        }

    }
}

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • Thanks for your response! This is fairly close, but by doing this, the content behind the overlay remains 100% visible. If you look at my second image closely, the content behind the loading overlay should be a little "dimmed", that's why I used the `Surface` and applied the alpha there. – BenjyTec Jan 27 '23 at 16:03
  • 1
    Thank you, `matchParentSize()` does the magic! – BenjyTec Jan 27 '23 at 17:45