Am I using Crossfade incorrectly? Not sure why add...
# compose
c
Am I using Crossfade incorrectly? Not sure why adding crossfade causes my progress bar to glitch like this. Code in thread.
This is the code for the above
Copy code
Column(
        Modifier.fillMaxSize().weight(1f),
        verticalArrangement = Arrangement.Bottom,
        horizontalAlignment = Alignment.CenterHorizontally) {
    Crossfade(targetState = viewModel.state.userIsLoading) {
        loading ->
        when (loading) {
            true -> {
                CircularProgressIndicator()
            }
            false -> {
                Button(
                        onClick = { viewModel.doThing() },
                ) { Text(text = "Do thing") }
            }
        }
    }
}
If I remove the crossfade... all is good.
Code in the good example
Copy code
Column(
    Modifier.fillMaxSize().weight(1f),
    verticalArrangement = Arrangement.Bottom,
    horizontalAlignment = Alignment.CenterHorizontally) {
    if (viewModel.state.userIsLoading) {
        CircularProgressIndicator()
    } else {
        Button(
            onClick = { viewModel.doThing() },
        ) { Text(text = "Do thing") }
    }
}
a
The sizes of the content for different states are different, so
Crossfade
resizes according to the content. When cross fading is in progress, both contents are shown so the biggest size is used, and after the button is disposed, the size shrinks to the progress indicator's size. To fix this,
Crossfade
need to have a fixed size.
c
Isn't the size fixed because the parent (Column) is a fixed size?
a
If you don't specify any size modifiers on the
Crossfade
it won't be automatically matching parent size.
c
Interesting. I will give this a whirl today. I've used Crossfade a few times and never got this. I wonder if there's a way to simplify my composable. Maybe get rid of the column? Thanks @Albert Chang
z
Might also work to use
wrapContentSize
with center alignment on the progress indicator?
c
Haven't heard of that. I'll try that too once I'm back at my desk.
a
That may fix the horizontal position but heights are also different (it's not very obvious but you can see that in the video) so I think you need a fixed height anyway.
If the outer column only contains one child, you can simply replace it with a
Box
and put it inside
Crossfade
. Also
Modifier.fillMaxSize().weight(1f)
doesn't seem to make sense.
Modifier.fillMaxSize()
should be enough.
c
Okay. Unfortunately I had to go this route. Everything else I tried based on the above help did not work.
Copy code
Crossfade(
    modifier = Modifier.fillMaxSize().align(CenterHorizontally),
    targetState = viewModel.state.loading) { loading ->
    when (loading) {
        true -> {
            Box(
                Modifier.fillMaxSize(),
                contentAlignment = Alignment.BottomCenter) {
                MyCustomTheme { CircularProgressIndicator() }
            }
        }
        false -> {
            Box(
                Modifier.fillMaxSize(),
                contentAlignment = Alignment.BottomCenter) {
                MyButton(
                    onClick = { viewModel.doThing() },
                    text = "Do thing")
            }
        }
    }
}
This was more work than I thought. 😭
a
You can simply write this:
Copy code
Crossfade(targetState = viewModel.state.loading) { loading ->
    Box(
        Modifier.fillMaxSize(),
        contentAlignment = Alignment.BottomCenter
    ) {
        when (loading) {
            true -> MyCustomTheme { CircularProgressIndicator() }
            false -> MyButton(
                onClick = { viewModel.doThing() },
                text = "Do thing"
            )
        }
    }
}
Also I'm not sure if you need
Alignment.BottomCenter
but considering that the size of the button can grow or shrink according to the text's length and size I think using
Alignment.Center
may be better.
c
So the reason why I want this to be the bottom is that this is basically a button that should be "pinned" to the bottom of the screen. Here is a crappy drawing of the screen. So I actually originally had Column { Text("Start") Button() } and in order to get the button at the bottom I wrapped it in a column and gave it weight of 1.
a
You don't need a weight here because it's the last child of the column. You only need a weight if you want a child which is not the last to take as much space as possible while keeping children after it visible.
c
Your last snippet of code was perfect.
Works now and it isn't super messy. Thank you @Albert Chang for your time and knowledge on this.
👍 1