11

I want to create TextField with exact 3 lines:

destination

I want to see 3 lines even without any text in this TextField, i.e. I need a direct equivalent of EditText.lines in classic xml layout.

My not working code is:

OutlinedTextField(
            value = currentText,
            onValueChange = { currentText = it },
            label = { Text ("Label") },
            maxLines = 3,
            modifier = Modifier.fillMaxWidth().wrapContentHeight().padding(16.dp),
            singleLine = false
        )

Could you help me?

anil
  • 2,083
  • 21
  • 37

4 Answers4

10

We can show multiline edittext by setting height of OutlinedTextField. Following example is tested.

                OutlinedTextField(
                    modifier = Modifier
                        .fillMaxWidth().height(120.dp)
                        .padding(start = 15.dp, top = 10.dp, end = 15.dp)
                        .background(Color.White, RoundedCornerShape(5.dp)),
                    shape = RoundedCornerShape(5.dp),
                    value = text,
                    onValueChange = { text = it },
                    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
                    maxLines = 3,
                    textStyle = MaterialTheme.typography.caption
                )

Attached image below.

enter image description here

Bruno
  • 3,872
  • 4
  • 20
  • 37
Gaurav Pawar
  • 201
  • 3
  • 8
8

Starting from Starting from M2 1.4.0-alpha02 and M3 1.1.0-alpha02 you can use the minLines attribute in the TextField and OutlinedTextField:

OutlinedTextField(
    value = text,
    onValueChange = { text = it },
    label = { Text ("Label") },
    minLines = 3,
    maxLines = 3,
    modifier = Modifier.fillMaxWidth().wrapContentHeight().padding(16.dp)
)

enter image description here enter image description here

It can be used with M2 and M3.

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
6

There is a feature request for this feature, I suggest your star it and maybe comment on it since it hasn't been updated for a while.

Until then you can use this hack. I render an invisible text field with extra lines so that it occupies the right size, and then apply that size to the real text field. I also pass modifier and textStyle as keys for remember for heightUpdateNeeded so that if you change them, the height will be recalculated. If any other parameters you pass may change the size of the view, you should pass them to remember as well.

@Composable
fun MinLinesOutlinedTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    label: @Composable (() -> Unit)? = null,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = false,
    minLines: Int,
    maxLines: Int = Int.MAX_VALUE,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = MaterialTheme.shapes.small,
    colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
    val heightState = remember { mutableStateOf<Int?>(null) }
    var heightUpdateNeeded by remember(modifier, textStyle) { mutableStateOf(true) }
    val height = with(LocalDensity.current) {
        heightState.value?.toDp()
    } // to use if nullable unwrapping
    Box(modifier.height(IntrinsicSize.Min).width(IntrinsicSize.Min)) {
        if (heightUpdateNeeded) {
            OutlinedTextField(
                value = value + "\n".repeat(minLines),
                onValueChange = onValueChange,
                enabled = enabled,
                readOnly = readOnly,
                textStyle = textStyle,
                label = label,
                placeholder = placeholder,
                leadingIcon = leadingIcon,
                trailingIcon = trailingIcon,
                isError = isError,
                visualTransformation = visualTransformation,
                keyboardOptions = keyboardOptions,
                keyboardActions = keyboardActions,
                singleLine = singleLine,
                maxLines = maxLines,
                interactionSource = interactionSource,
                shape = shape,
                colors = colors,
                modifier = Modifier
                    .fillMaxSize()
                    .alpha(0f)
                    .onSizeChanged {
                        heightUpdateNeeded = false
                        println("onSizeChanged $it")
                        heightState.value = it.height
                    }
            )
        }
        if (height != null) {
            OutlinedTextField(
                value = value,
                onValueChange = onValueChange,
                enabled = enabled,
                readOnly = readOnly,
                textStyle = textStyle,
                label = label,
                placeholder = placeholder,
                leadingIcon = leadingIcon,
                trailingIcon = trailingIcon,
                isError = isError,
                visualTransformation = visualTransformation,
                keyboardOptions = keyboardOptions,
                keyboardActions = keyboardActions,
                singleLine = singleLine,
                maxLines = maxLines,
                interactionSource = interactionSource,
                shape = shape,
                colors = colors,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(height)
            )
        }
    }
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • 1
    Thank you! So Google, Compose is ready for production and we can use it in our projects? – anil Sep 03 '21 at 08:25
  • @anil it's ready to use, but that doesn't mean it has everything you might need or that it's bug-free. Android XML has been in development for over a decade, so it's not a quick thing to port all the functionality. In most cases, you can find a workaround, like here. The only critical bug I've encountered and couldn't defeat is [scroll lazy view to highlighted text box](https://issuetracker.google.com/issues/192043120) – Phil Dukhov Sep 03 '21 at 08:33
  • Try to input some text into TextField with multi lines. Delete something, replace cursor and so on. There are a lot of glitches there even on the latest Android versions. Will I release it on real users? No way! Will rewrite on old xml. – anil Sep 03 '21 at 08:47
  • 2
    @anil I am giving you an idea of how you can solve this problem. I'm not doing the work for you, that's why I'm not thinking through all the corner cases you might encounter. If you know xml well - you can do it your way. I believe you can develop applications much faster with Compose, but you need to learn at a sufficient level before it becomes true. – Phil Dukhov Sep 03 '21 at 09:05
0

I had the same problem, and I found the solution as of now, basically, google has already solved the issue but it is in the Alpha release (androidx.compose.foundation:foundation:1.4.0-alpha01).

And to solve the issue I just copy paste HeightInLinesModifier.kt to our project and it is working fine by using Modifier.heightInLines. And as soon as it will become available in stable release We just need to delete this File from our project and change the import and we are good to go

Gauraw Negi
  • 561
  • 5
  • 8