Shreyash.K
Shreyash.K

Reputation: 1138

Last composables in Row() get squeezed (Jetpack Compose)

I am trying to create a custom search bar; in which I am using Row() composable as a container for all the other elements. Here the last FloatingActionButton gets squeezed but I want the TextField to be flexible so that it gets shortened to accommodate the remaining elements.

Last element squeezed in Row

I already know some workarounds to this but I want a better solution. See below for the known workarounds and their drawbacks.


@Preview(showBackground = true, widthDp = 410)
@Composable
fun MyComposable() {
    Row(Modifier.fillMaxWidth()) {
        TextField(value = "Search", onValueChange = {})
        FloatingActionButton(onClick = {}) {Icon(Icons.Filled.SkipNext, contentDescription = null)}
        FloatingActionButton(onClick = {}) {Icon(Icons.Filled.Close, contentDescription = null)}
        FloatingActionButton(onClick = {}) {Icon(Icons.Filled.Home, contentDescription = null)}
    }
}

Known workarounds:

  1. Using ConstraintLayout (Drawback: Complicated. Seems like overkill in many situations.)
  2. Using CompositionLocalProvider to provide a RTL LocalLayoutDirection. (Drawback: Seems hacky. All the layouts of child components become RTL. For example textfield icons and text placement.)
  3. Specifying fixed width (or weights) to the last element. (Drawback: This makes the second last element to squeeze and forces me to hardcode width which cannot be done on some elements like Button as its width is determined by localized text in it.)

Upvotes: 9

Views: 3374

Answers (2)

Bartek Lipinski
Bartek Lipinski

Reputation: 31448

There's also another, similar case. I'd argue it's even less straightforward.

  1. The left-most UI (text) element shouldn't fill the available space,
  2. The right-most UI (icon v) element should stay glued to the text, but...
  3. ... it shouldn't be pushed off the screen when the text fills the entire available space.

Here's how you can accomplish that:

Row {
  Text(
    text = text,
    modifier = Modifier.align(Alignment.CenterVertically).weight(1f, fill = false),
  )
  Icon(
    painter = painterResource(R.drawable.trailingIcon),
    contentDescription = null,
    modifier = Modifier
      .align(Alignment.Top)
      .size(20.dp),
  )
}

Upvotes: 0

Gabriele Mariotti
Gabriele Mariotti

Reputation: 364451

You can apply the weight(1f) to the TextField:

Row(Modifier.fillMaxWidth()) {
        TextField(
            modifier = Modifier.weight(1f),
            value = "Search", onValueChange = {})

        FloatingActionButton(onClick = {}) {Icon(Icons.Filled.SkipNext, contentDescription = null)}
        FloatingActionButton(onClick = {}) {Icon(Icons.Filled.Close, contentDescription = null)}
        FloatingActionButton(onClick = {}) {Icon(Icons.Filled.Home, contentDescription = null)}
    }

enter image description here enter image description here

Upvotes: 15

Related Questions