nasibeyyubov
nasibeyyubov

Reputation: 2631

remove default padding on jetpack compose textfield

I want to customize TextField composable in Jetpack Compose. I am trying to achieve the result in the image below, but somehow TextField has some default paddings which i couldn't find how to change values of. I want to remove default paddings and customize it

(The image on the right one is the result i achieved. I drew a border so that you can see it has padding, btw below that TextField are just Text composables, they aren't TextFields)

enter image description here enter image description here

Below is my TextField code

TextField(
    value = "",
    onValueChange = {},
    modifier = Modifier
        .weight(1F)
        .padding(0.dp)
        .border(width = 1.dp, color = Color.Red),
    placeholder = {
        Text(
            "5555 5555 5555 5555", style = TextStyle(
                color = Color.Gray
            )
        )
    },
    colors = TextFieldDefaults.textFieldColors(
        backgroundColor = Color.Transparent,
        unfocusedIndicatorColor = Color.Transparent,
        focusedIndicatorColor = Color.Transparent
    ),
)

Upvotes: 80

Views: 52989

Answers (11)

Kontick
Kontick

Reputation: 123

You need to add/update this dependency (version should be 1.4.0-alpha03 or newer):

implementation("androidx.compose.material3:material3:1.4.0-alpha03")

Then, in your code, you can remove any padding and set height without text being cut as follows:

val state = rememberTextFieldState()
OutlinedTextField(
   modifier = Modifier.height(30.dp),
   state = state,
   contentPadding = PaddingValues()
)

Documentation

Upvotes: 0

Saurav Munankarmi
Saurav Munankarmi

Reputation: 11

You can remove the minimum height, by using Modifier.heightIn(min = 0.dp). This should fix your "default padding" issue.

Upvotes: 1

jeran
jeran

Reputation: 529

In the latest alpha release (androidx.compose.material:material:1.2.0-alpha04) they exposed TextFieldDefaults.TextFieldDecorationBox.

This is the implementation of the decorationBox composable used in the material TextField implementation.

You can use it as follows:

val interactionSource = remember { MutableInteractionSource() }
BasicTextField(
    value = value,
    onValueChange = onValueChange,
    modifier = modifier,
    visualTransformation = visualTransformation,
    interactionSource = interactionSource,
    enabled = enabled,
    singleLine = singleLine,
) { innerTextField ->
    TextFieldDefaults.DecorationBox(
        value = value,
        visualTransformation = visualTransformation,
        innerTextField = innerTextField,
        singleLine = singleLine,
        enabled = enabled,
        interactionSource = interactionSource,
        contentPadding = PaddingValues(0.dp), // this is how you can remove the padding
    )
}

This will allow you to remove the padding but still get the rest of the features that come with TextField.

Remember to use the same MutableInteractionSource for both the BasicTextField and the TextFieldDefaults.TextFieldDecorationBox.

The official documentation I linked to above shows more examples if its usage.

Upvotes: 50

Alessandro Verrecchia
Alessandro Verrecchia

Reputation: 97

The default TextOverflow value in Text composables is TextOverflow.Clip

If your text is well centered, but some of the top or bottom is clipped you can update with the following exemple :

placeholder = {
        Text(
            "5555 5555 5555 5555", style = TextStyle(
                color = Color.Gray
            ), overflow = TextOverflow.Visible
        )
    }

Visual representation example:

Visual representation example

Upvotes: 0

Bréndal Teixeira
Bréndal Teixeira

Reputation: 1175

Using

...
decorationBox{
     TextFieldDefaults.TextFieldDecorationBox(
          ....
     ) 

required me to add the anotation @OptIn(ExperimentalMaterialApi::class) which seems to not be a good aproach for a release scenario. Instead, I could get the result I as expecteing by the following implementation:

@Composable
fun Input(
    text: TextFieldValue = TextFieldValue(),
    onValueChanged: (TextFieldValue) -> Unit = { },
    keyboardType: KeyboardType = KeyboardType.Text,
    imeAction: ImeAction = ImeAction.Done,
    isEnable: Boolean = true,
    singleLine: Boolean = true,
    shape: Shape = rounded,
    autoCorrect: Boolean = false,
    innerPadding: PaddingValues = PaddingValues(15.dp, 7.dp)
) {
    val focusManager = LocalFocusManager.current
    val fontSize = 16.sp

    BasicTextField(
        value = text,
        onValueChange = onValueChanged,
        Modifier
            .clip(shape)
            .border(1.dp, Color.Gray, shape)
            .background(Color.White),
        textStyle = TextStyle(color = Color.Black, fontSize = fontSize),
        enabled = isEnable,
        singleLine = singleLine,
        keyboardOptions = KeyboardOptions(
            KeyboardCapitalization.None,
            autoCorrect,
            keyboardType,
            imeAction
        ),
        keyboardActions = KeyboardActions(
            onAny = {
                focusManager.clearFocus()
            }
        ),
        decorationBox = {

            Box(
                modifier = Modifier.padding(innerPadding)
            ) {

                if(text.text.isBlank()) {
                    Text(
                        text = "Search",
                        style = TextStyle(color = Color.Black, fontSize = fontSize)
                    )
                }
                it()
            }
        }
    )
}

Hope it helps somebody.

Upvotes: 0

Pepijn
Pepijn

Reputation: 1477

I wanted to cut off the 16.dp at the start. I managed to this in the following way:

BoxWithConstraints(modifier = Modifier
          .clipToBounds()
) {
    TextField(modifier = Modifier
        .requiredWidth(maxWidth+16.dp)
        .offset(x=(-8).dp))
}

Upvotes: 6

LV Channel
LV Channel

Reputation: 39

I solved this problem by coping all source code from TextField and replace this lines of code :

              val paddingToIcon = TextFieldPadding - HorizontalIconPadding
//            val padding = Modifier.padding(
//                start = if (leading != null) paddingToIcon else TextFieldPadding,
//                end = if (trailing != null) paddingToIcon else TextFieldPadding
//            )
            val padding = Modifier.padding(
                start = if (leading != null) paddingToIcon else 0.dp,
                end = if (trailing != null) paddingToIcon else 0.dp
            )

And this work great!

Upvotes: 0

Phil Dukhov
Phil Dukhov

Reputation: 88152

You can use BasicTextField, it's a plain text field without any decorations. Note that it doesn't have placeholder/hint too, you have to implement those by yourself if you need.

BasicTextField(value = "", onValueChange = {}, Modifier.fillMaxWidth())

Since 1.2.0-alpha04 it's much easier to make your BasicTextField look like TextField or OutlinedTextField. You can copy source code of TextField, which is pretty short since most of logic was moved into TextFieldDefaults.TextFieldDecorationBox, and pass the needed padding value into contentPadding parameter of TextFieldDefaults.TextFieldDecorationBox.

Upvotes: 55

Pietrek
Pietrek

Reputation: 1761

You can put your TextField in a Box and apply modifiers, e.g.

Box(
        modifier = Modifier.background(
            shape = RoundedCornerShape(percent = 10),
            color = colorBackgroundGray
        )
    ) {
        TextField(
            value = text,
            onValueChange = onValueChange,
            modifier = Modifier.fillMaxWidth().padding(8.dp, 0.dp, 0.dp, 0.dp)...
}

Upvotes: -2

nasibeyyubov
nasibeyyubov

Reputation: 2631

Thank you all, i did use BasicTextField and achieved the result i wanted :)

@Composable
fun BottomOutlineTextField(placeholder: String, value: String, onValueChange: (String) -> Unit) {

    BasicTextField(
        modifier = Modifier.fillMaxWidth(),
        value = value,
        onValueChange = onValueChange,
        textStyle = TextStyle(
            color = if (isSystemInDarkTheme()) Color(0xFF969EBD) else Color.Gray
        ),
        decorationBox = { innerTextField ->
            Row(modifier = Modifier.fillMaxWidth()) {
                if (value.isEmpty()) {
                    Text(
                        text = placeholder,
                        color = if (isSystemInDarkTheme()) Color(0xFF969EBD) else Color.Gray,
                        fontSize = 14.sp
                    )
                }
            }
            innerTextField()
        }
    )
}

Upvotes: 19

Richard Onslow Roper
Richard Onslow Roper

Reputation: 6863

Actually that is innate, it follows material guidelines. If you wish to disable it, an alternative could be to set the height of the TextField explicitly, and matching it with the font size of the text. That way it will only extend till the text does. Another way would be to look at the source of TextField. You could just copy the source and make modifications to meet your requirements. The former sounds like an easy fix, however, the latter is no big deal as well. It is doable, and is a recommended practice to customize behavior for your needs. Also, just as a side note, I don't think it is a good idea to disable that padding. It was added to design guidelines since it seems pretty sensible and natural to have it. Sometimes we find some designs attractive when we think about them but they aren't as good when seen implemented.

Upvotes: -4

Related Questions