skip to Main Content

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?

2

Answers


  1. It happens because Row and Column when measuring composables uses total space – space used by other children. Since Text can be measured with whole remaining space IconButton gets 0 maxWidth to be measured between 0 and maxWidth it gets 0 width.

    Solution is to use Modifier.weight(1f, fill = false) to measure Text last. Composables with weight are measured after other Composables. But since you used Spacer with Modifier.weight space will be divided equally.

    For that you can change it like this.

    @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
            ) {
                Row(
                    modifier = Modifier.weight(1f, false)
                ) {
                    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"
                    )
                }
            }
        }
    }
    

    By changing as above Row first measures IconButton then inner Row is measured since Spacer used inside it wit fill when Text is smaller it increases width to match outer Row.

    Login or Signup to reply.
  2. 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"
                    )
                }
            }
        }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search