2

Is there a way to set the trailing/leading icons and the text on the same level? On default it is not as shown in the image below. I tried changing the fontStyle parameter in TextField but no success. The text is shown higher than the icons

enter image description here

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Icon
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.singleWindowApplication

fun main() = singleWindowApplication {
    var text by remember { mutableStateOf("TEXT") }
    
    OutlinedTextField(
        value = text,
        onValueChange = { text = it },
        modifier = Modifier.fillMaxWidth(),
        leadingIcon = {
            Icon(contentDescription = null,
                 imageVector = Icons.Default.ArrowForward)
        },
        trailingIcon = {
            Icon(contentDescription = null,
                 imageVector = Icons.Default.ArrowForward)
        })
}

Johann
  • 27,536
  • 39
  • 165
  • 279
Zen1000
  • 147
  • 9

1 Answers1

2

There are several solutions. For desktop Compose, offset the icons. For mobile Compose, adjust the baseline. And finally, just create a custom TextField.

The icons may have extra padding at the bottom. It could also be that the icons and text are always aligned to the top. You could replace the icons with ones that have no bottom padding or shift the icons up. You can tell that the icons are affecting the vertical alignment because if you comment out your icons, the text does center vertically. You could also try reducing the size of the icons.

On desktop Compose, shift the icons up:

OutlinedTextField(
     value = text,
     onValueChange = { text = it },
     modifier = Modifier.fillMaxWidth(),
     leadingIcon = {
          Icon(
                modifier = Modifier.offset(y = -3.dp),
                contentDescription = null,
                imageVector = Icons.Default.ArrowForward
          )
     },
     trailingIcon = {
          Icon(
                modifier = Modifier.offset(y = -3.dp),
                contentDescription = null,
                imageVector = Icons.Default.ArrowForward
          )
     })

On mobile devices, you can adjust the baseline of the text:

OutlinedTextField(
    value = text,
    textStyle = TextStyle(baselineShift = BaselineShift(-0.2f)),
    onValueChange = { text = it },
    modifier = Modifier.fillMaxWidth(),
    leadingIcon = {
        Icon(
            contentDescription = null,
            imageVector = Icons.Default.ArrowForward
        )
    },
    trailingIcon = {
        Icon(
            contentDescription = null,
            imageVector = Icons.Default.ArrowForward
        )
    })

Here is also a custom TextField:

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            CustomTextField(
                initialText = "cool",
                onValueChange = {

                },
                onLeftButtonClick = {

                },
                onRightButtonClick = {

                }
            )
        }
    }
}

@Composable
fun CustomTextField(
    initialText: String,
    onValueChange: (text: String) -> Unit,
    onLeftButtonClick: () -> Unit,
    onRightButtonClick: () -> Unit
) {

    var text by remember { mutableStateOf(initialText) }

    Row(
        modifier = Modifier

            .fillMaxWidth()
            .wrapContentSize()
            .background(color = Color.White, shape = RoundedCornerShape(8.dp))

            .border(width = 1.dp, shape = RoundedCornerShape(8.dp), color = Color(0xFF585858))
    ) {

        ConstraintLayout(
            modifier = Modifier.fillMaxWidth()
        ) {

            val (left, mid, right) = createRefs()

            IconButton(onClick = onLeftButtonClick,
                modifier = Modifier.constrainAs(left) {
                    start.linkTo(parent.start, margin = 10.dp)
                    top.linkTo(parent.top)
                    bottom.linkTo(parent.bottom)
                }) {
                Icon(
                    contentDescription = null,
                    imageVector = Icons.Default.ArrowForward,
                )
            }


            IconButton(onClick = onRightButtonClick,
                modifier = Modifier.constrainAs(right) {
                    end.linkTo(parent.end, margin = 10.dp)
                    top.linkTo(parent.top)
                    bottom.linkTo(parent.bottom)
                }) {
                Icon(
                    contentDescription = null,
                    imageVector = Icons.Default.ArrowForward,
                )
            }

            TextField(
                value = text,
                onValueChange = {
                    text = it
                    onValueChange(it)
                },
                colors = TextFieldDefaults.textFieldColors(
                    backgroundColor = Color.White
                ),
                modifier = Modifier
                    .offset(y = 4.dp)
                    .constrainAs(mid) {
                        start.linkTo(left.end, margin = 10.dp)
                        top.linkTo(parent.top)
                        end.linkTo(right.start, margin = 10.dp)
                        bottom.linkTo(parent.bottom)
                        width = Dimension.fillToConstraints
                    })
        }
    }
Johann
  • 27,536
  • 39
  • 165
  • 279
  • I adjusted the baseline as you suggested, but it does not change anything. Tried also with higher values but stays the same – Zen1000 Nov 27 '21 at 11:26
  • I only tried it on a mobile device where it works. It probably doesn't work on the desktop version of Compose. – Johann Nov 27 '21 at 11:53
  • I updated the code to show an alternative solution for desktop apps. – Johann Nov 27 '21 at 12:04
  • thanks, I'll do it this way until there is something that will automatically align everything vertically – Zen1000 Nov 27 '21 at 12:21
  • I also added a custom TextField as an alternate solution. You have full control over this. – Johann Nov 27 '21 at 13:37
  • I have now also tested my example in Android (which does not work on the desktop) and it works as expected, everything is aligned. There must be a bug in the desktop compose version. – Zen1000 Nov 27 '21 at 16:37