kotlinandroid-studiomaterial-uiandroid-jetpack-compose

Composable Item going off the width view


I'm creating an app to studies and I got an "error". I looked for help and saw some posts here and on another sites, but nothing works to me.

The last item from a Composable Row is going off the width view when the body text is "larger", as you can see here. I can click in the item, but it's invisible: enter image description here


import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.cleanarchtodo.ui.theme.CleanArchToDoTheme

@Composable
fun ToDoCard(
    modifier: Modifier = Modifier,
    text: String = "",
    checked: Boolean = false,
    onCheckedChange: () -> Unit,

    ) {
    ElevatedCard(
        modifier = modifier
            .fillMaxWidth()
            .padding(
                vertical = 4.dp,
                horizontal = 12.dp
            ),
        elevation = CardDefaults.cardElevation(
            defaultElevation = 8.dp
        )
    ) {
        Row(modifier = Modifier
            .fillMaxWidth(),
            verticalAlignment = Alignment.Top,
            horizontalArrangement = Arrangement.Start
        ) {
            Checkbox(
                checked = checked,
                onCheckedChange = { onCheckedChange() }
            )
            Text(
                text = text,
                fontSize = 20.sp,
                maxLines = 3,
                overflow = TextOverflow.Ellipsis
            )
            Spacer(modifier = Modifier.weight(1f))
            IconButton(
                onClick = { }
            ) {
                Icon(
                    imageVector = Icons.Default.Delete,
                    contentDescription = "Delete ToDo"
                )
            }
        }
    }
}

@Preview(
    showBackground = true
)
@Composable
fun PreviewToDoCard() {
    CleanArchToDoTheme {
        ToDoCard(
            text = "Buy bananas Buy bananas Buy bananas",
            onCheckedChange = {}
        )
    }
}

Somebody can help me?


Solution

  • Text widget grows in size to accomodate the size of the text inside it, until it runs out of the parent width. With a very long text like in your case, no space is left for the button to the right
    To fix this, you can add Modifier.weight(1f) to your Text, so it takes up all free space, but is laid out after all other elements, including the button. Also with this approach, you can drop the Spacer(Modifier.weight(1f) after the Text, because the new Text basically combines these two functions

    @Composable
    fun ToDoCard(
        modifier: Modifier = Modifier,
        text: String = "",
        checked: Boolean = false,
        onCheckedChange: () -> Unit,
    
        ) {
        ElevatedCard(
            modifier = modifier
                .fillMaxWidth()
                .padding(
                    vertical = 4.dp,
                    horizontal = 12.dp
                ),
            elevation = CardDefaults.cardElevation(
                defaultElevation = 8.dp
            )
        ) {
            Row(modifier = Modifier
                .fillMaxWidth(),
                verticalAlignment = Alignment.Top,
                horizontalArrangement = Arrangement.Start
            ) {
                Checkbox(
                    checked = checked,
                    onCheckedChange = { onCheckedChange() }
                )
                Text(
                    text = text,
                    fontSize = 20.sp,
                    maxLines = 3,
                    overflow = TextOverflow.Ellipsis,
                    textAlign = TextAlign.Start,
                    modifier = Modifier.weight(1f),
                )
                IconButton(
                    onClick = { }
                ) {
                    Icon(
                        imageVector = Icons.Default.Delete,
                        contentDescription = "Delete ToDo"
                    )
                }
            }
        }