I'm implementing a theme chooser screen for my app. The idea is to provide various themes that the user can choose from and show previews of two screens so that the user can see how the theme will look after selecting it.
I display this home screen as a preview:
This is how my theme chooser screen looks:
I want to scale down the content of the home screen to display the entire home screen content within the available area of the theme chooser preview.
I've tried using Modifier.scale(0.4f)
and Modifier.graphicsLayer(scaleX = 0.4f, scaleY = 0.4f)
, but this only scales down what's already visible.
One idea that seems to work is using a local provider to provide a scale factor to the Compose UI like this:
val LocalScaleFactor = compositionLocalOf { 1f }
@Composable
fun ScaleFactorProvider(
scaleFactor: Float = 1f,
content: @Composable () -> Unit,
) {
CompositionLocalProvider(
LocalScaleFactor provides scaleFactor,
content = content
)
}
val Int.scaleDp: Dp
@Composable
get() = (this * localScaleFactor).dp
val Int.scaleSp: TextUnit
@Composable
get() = (this * localScaleFactor).sp
val localScaleFactor: Float
@Composable get() = LocalScaleFactor.current
ScaleFactorProvider(0.4f) {
HomeScreenPreview()
}
While this method works, it requires extensive code changes. I have to use scaleDp
and scaleSP
everywhere, and for some views like Icon
, which I don't usually provide any size and just use the default size, I now have to define the size. This is quite inconvenient.
Is there an alternative way to scale down the dimensions of the entire UI tree to fit the available parent size in Jetpack Compose?
Edit 1:
I've tried what @Leviathan suggested in the comment. It works but it makes it hard to make the UI responsible. My current UI looks something like this
- Column
- Row
- Box 1f weight
- Box 1f weight
- Rest of the UI
- Row
Now I have to move the content of the row outside
- Box
- Column
- Empty Box 1f weight
- Rest of the UI
- Box left preview
- Box right preview
- Column
After scaling down, both previews will be at the centre and I have to provide x and y offsets to place where I want them to be.
The issue with this method is that since the preview box is bound to the parent, the alignments could be off based on the user device dimension.