In our application, there are many custom views that all are card with 3 slots header, content and bottom part, so I thought we can handle it with a scaffold inside the card except having many if/else conditions
So I created this base composable function ->
@Composable
fun DynamicTile(
modifier: Modifier = Modifier,
headContent: @Composable () -> Unit,
mainContent: @Composable (PaddingValues) -> Unit = { },
bottomContent: @Composable () -> Unit = { }
) {
Card( modifier = modifier) {
Scaffold(
topBar = headContent,
content = mainContent,
bottomBar = bottomContent
)
}
}
then different implementation for different purposes, I mention here two purposes e.g. showing specific image, animation, map and ... ->
for this one you should add your local drawable to image to compile it
@Composable
fun TileTeaser( modifier: Modifier = Modifier) {
with(entity) {
DynamicTile(
// modifier = modifier.then(Modifier.height(250.dp)),
headContent = {
Text(
text = "headline",
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, top = 8.dp)
)
},
mainContent = {
val painter = rememberImagePainter(
data = painterResource(R.drawable.ds_ic_add))
Image(
contentScale = ContentScale.Crop,
painter = painter,
modifier = modifier,
contentDescription = null
)
},
bottomContent = {
Box(modifier = Modifier.fillMaxWidth()) {
Button(
onClick = { }, modifier = Modifier
.align(Alignment.Center)
.wrapContentSize()
) {
Text(text = "Button")
}
}
}
}
)
}
}
And this one for animation with Lottie, you should add local raw to compile it
@Composable
fun TileAnimation(modifier: Modifier = Modifier) {
DynamicTile(
modifier = modifier.then(Modifier.height(300.dp)),
headContent = {
Text(
text = "headline",
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, top = 8.dp)
)
},
mainContent = {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.sth))
Card(
modifier = Modifier
.height(183.dp)
.then(modifier),
shape = RoundedCornerShape(0.dp)
) {
LottieAnimation(
composition = composition,
modifier = modifier
.fillMaxSize(),
contentScale = ContentScale.Crop,
)
}
},
bottomContent = {
Box(modifier = Modifier.fillMaxWidth()) {
Button(
onClick = { }, modifier = Modifier
.align(Alignment.Center)
.wrapContentSize()
) {
Text(text = "Button")
}
}
}
)
}
Then I load them in column like this
@Composable
fun LoadScreen() {
Column(
modifier = Modifier
.padding(16.dp)
.verticalScroll(rememberScrollState())
) {
Text(text = "Teaser")
TileTeaser(
modifier = Modifier.padding(top = 16.dp)
)
Text(
text = "Animation",
modifier = Modifier.padding(top = 16.dp)
)
TileAnimation(modifier = Modifier.padding(vertical = 16.dp))
}
}
As you see if I comment the Modifier.height of the card, it crashes with this error ->
java.lang.IllegalArgumentException: Can't represent a size of 2147483563 in Constraints
at androidx.compose.ui.unit.Constraints$Companion.bitsNeedForSize(Constraints.kt:408)
at androidx.compose.ui.unit.Constraints$Companion.createConstraints-Zbe2FdA$ui_unit_release(Constraints.kt:368)
Kotlin version 1.6.10 and compose 1.1.0 and this is lottie library ->
implementation "com.airbnb.android:lottie-compose:4.2.2"
BTW, you can download Lottie file from here
Thank you in advance for your help
TL;DR
Don't put a Scaffold
inside a Card
inside a scrollable content. :)
If we take a deeper look into Scaffold
code we will see that it's actually creating a ScaffoldLayout
that will create a SubcomposeLayout
that uses constraints and more specifically the following width and height:
val layoutWidth = constraints.maxWidth
val layoutHeight = constraints.maxHeight
Now, if no predefined values was set to the above layoutWidth
and layoutHeight
they will be equal to Int.MAX_VALUE
which is 2147483647 which is what you see in your IllegalArgumentException
(give or take).
When you use Scaffold the right way, usually as the root of your UI, Android do the magic for you and calculate the correct size.
My suggestion, replace the Scaffold with another type of layout or if it's not enough a custom layout:
https://developer.android.com/jetpack/compose/layouts/custom