Search code examples
androidtextandroid-jetpack-compose

Force Jetpack Compose to display 2 Text() Components one below other


Hi I have such piece of code: it draws movie card. The problem, which I have, is that only one of two Text components are printed. I tried many versions of modifications, but always there is only one text. Could you explain me why? :(

item {
    key(movie.id) {
        Box(contentAlignment = Alignment.CenterStart) {
            StandardCardLayout(
                modifier = Modifier
                    .aspectRatio(1.25f)
                    .padding(8.dp)
                    .then(
                        if (index == 0)
                            Modifier.focusOnInitialVisibility(isFirstItemVisible)
                        else Modifier
                    ),
                imageCard = {
                    CardLayoutDefaults.ImageCard(
                        shape = CardDefaults.shape(shape = JetStreamCardShape),
                        border = CardDefaults.border(
                            focusedBorder = Border(
                                border = BorderStroke(
                                    width = JetStreamBorderWidth,
                                    color = MaterialTheme.colorScheme.onSurface
                                ),
                                shape = JetStreamCardShape
                            ),
                            pressedBorder = Border(
                                border = BorderStroke(
                                    width = JetStreamBorderWidth,
                                    color = MaterialTheme.colorScheme.border
                                ),
                                shape = JetStreamCardShape
                            ),
                        ),
                        scale = CardDefaults.scale(focusedScale = 1f),
                        onClick = { onMovieSelected(movie) },
                        interactionSource = it
                    ) {
                        AsyncImage(
                            model = ImageRequest.Builder(LocalContext.current)
                                .data(movie.posterUri)
                                .crossfade(true)
                                .build(),
                            contentDescription = StringConstants
                                .Composable
                                .ContentDescription
                                .moviePoster(movie.name),
                            contentScale = ContentScale.Crop,
                            modifier = Modifier.fillMaxWidth().aspectRatio(1.77f)
                        )
                        Text(
                            text = movie.name.take(20),
                            style = MaterialTheme.typography.bodySmall.copy(
                                fontWeight = FontWeight.SemiBold,
                                lineHeight = 2.em
                            ),
                            textAlign = TextAlign.Center,
                            modifier = modifier
//                                                .alpha(1f)
                                .fillMaxWidth()
                                .wrapContentHeight(align = Alignment.Top, unbounded = true)
//                                                .padding(top = 26.dp)
                                .background(color = Color.Black)
                                .align(Alignment.TopCenter)
                            ,
                            maxLines = 2,
                            overflow = TextOverflow.Ellipsis,
                            color = Color.White,
                            lineHeight = 15.sp,
                            fontSize = 10.sp,
                        )
                        Text(
                            text = "(${movie.stars}) " + movie.releaseDate,
                            style = MaterialTheme.typography.bodySmall.copy(
                                fontWeight = FontWeight.SemiBold
                            ),
                            textAlign = TextAlign.Center,
                            modifier = modifier
//                                                .alpha(1f)
                                .fillMaxWidth()
                                .wrapContentHeight(align = Alignment.Top, unbounded = true)
//                                                .padding(top = 26.dp)
                                .background(color = Color.Black)
                                .align(Alignment.BottomCenter)
                            ,
                            maxLines = 2,
                            overflow = TextOverflow.Ellipsis,
                            color = Color.White,
                            lineHeight = 15.sp,
                            fontSize = 10.sp
                        )
                    }
                },
                title = {},
            )
        }
    }
}

I tried to use:

Modifier.wrapContentHeight
Modifier.height
Modifier.aspectRatio
lineHeight
etc...

Preview on single 'item'

As you can see on the image, it prints only one text. I know, that I could print it with "\n" escape sequence, and use one Text component, but I need different styles for each text.

EDIT: My layout is:

Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxHeight()
    ) {
        TvLazyVerticalGrid(
            columns = TvGridCells.Fixed(4),
            contentPadding = PaddingValues(
                bottom = JetStreamBottomListPadding,
//                horizontal = 16.dp, vertical = 8.dp
            ),
            state = gridState,
            modifier = modifier
        ) {
...
movieList.forEachIndexed { index, movie ->
    item {
        key(movie.id) {
            Box(contentAlignment = Alignment.CenterStart) {

EDIT2:

Ok, thanks, I've found, I had .fillMaxHeigh() in external component execution.


Solution

  • It all depends on what CardLayoutDefaults.ImageCard does with the content that is provided for its last parameter. Despite the name it doesn't seem to use a specific strategy to layout its children, so all children (that is the AsyncImage and two Texts) are placed on top of each other.

    That can easily be fixed by providing your own layout component. It can be placed either inside CardLayoutDefaults.ImageCard wrapping the content or directly in the code from your example wrapping the three elements.

    If the elements should be arranged vertically you should use a Column as layout component. If they should be arranged horizontally, wrap them in a Row. There are more layouts available. See the documentation if you want to learn more about layouts.