最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - How to align Jetpack Compose OutlinedTextField label without affecting border when field is populated? - Stack Overflo

programmeradmin2浏览0评论

I have an OutlinedTextField with label text. When the field is empty, I want the label hint aligned to the end of the field, like this: .

However, the only way I've found to do this is by expanding the text to its maximum width so that the alignment has an effect. However, when the text field has some value and the label gets moved to the top border, the border is interrupted because the label is at its max width (the border should extend all the way to the 'F'):

I've tried a couple different things:

  1. Setting the width of the Text composable to maximum available (border is still interrupted when field has value)
  2. Setting the width of the Text composable to the intrinsic max (Text composable stays the same width and is not aligned correctly).
  3. Wrapping the Text in a Box, making the box as wide as possible and using the contentAlign parameter of the Box (same as 1)

Is there any way to align the label without affecting the border? The code below results in incorrect alignment but correct border behavior:

@Composable
fun TextFieldLabel(text: String, modifier: Modifier = Modifier) {

// Wrapping in a box has the same behavior as adding .fillMaxWidth() to the Text modifier
//    Box(modifier = modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) {

    Text(
        text = text,
        textAlign = TextAlign.End,
        modifier = modifier // adding .fillMaxWidth() will correct the alignment but cause border to be cut short
                            // adding .width(IntrinsicSize.Max) gives incorrect alignment but border extends all the way
    )

//    }
}

@Composable
fun CurrencyInputTextField(
    modifier: Modifier = Modifier
) {
    OutlinedTextField(
        value = "",
        label = { TextFieldLabel(label) },
        prefix = {Text(text = "$")},
        onValueChange = {},
        singleLine = true,
        textStyle = MaterialTheme.typography.bodyLarge.copy(textAlign = TextAlign.End),
        modifier = modifier
    )
}

I have an OutlinedTextField with label text. When the field is empty, I want the label hint aligned to the end of the field, like this: .

However, the only way I've found to do this is by expanding the text to its maximum width so that the alignment has an effect. However, when the text field has some value and the label gets moved to the top border, the border is interrupted because the label is at its max width (the border should extend all the way to the 'F'):

I've tried a couple different things:

  1. Setting the width of the Text composable to maximum available (border is still interrupted when field has value)
  2. Setting the width of the Text composable to the intrinsic max (Text composable stays the same width and is not aligned correctly).
  3. Wrapping the Text in a Box, making the box as wide as possible and using the contentAlign parameter of the Box (same as 1)

Is there any way to align the label without affecting the border? The code below results in incorrect alignment but correct border behavior:

@Composable
fun TextFieldLabel(text: String, modifier: Modifier = Modifier) {

// Wrapping in a box has the same behavior as adding .fillMaxWidth() to the Text modifier
//    Box(modifier = modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) {

    Text(
        text = text,
        textAlign = TextAlign.End,
        modifier = modifier // adding .fillMaxWidth() will correct the alignment but cause border to be cut short
                            // adding .width(IntrinsicSize.Max) gives incorrect alignment but border extends all the way
    )

//    }
}

@Composable
fun CurrencyInputTextField(
    modifier: Modifier = Modifier
) {
    OutlinedTextField(
        value = "",
        label = { TextFieldLabel(label) },
        prefix = {Text(text = "$")},
        onValueChange = {},
        singleLine = true,
        textStyle = MaterialTheme.typography.bodyLarge.copy(textAlign = TextAlign.End),
        modifier = modifier
    )
}
Share Improve this question asked Mar 26 at 10:45 theasianpianisttheasianpianist 4316 silver badges17 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Maybe this can help, what if you add a top line just to complete the space?

You add a onChangeSize listener, just to know the label spacing and use it as padding for the top line

@Composable
fun TextFieldLabel(
    text: String,
    modifier: Modifier = Modifier,
    onChangeSize: (Dp)->Unit,
) {

    Box(
        modifier = modifier
            .fillMaxWidth(),
    ) {

        val density = LocalDensity.current
        Text(
            text = text,
            textAlign = (TextAlign.End),
            modifier = Modifier
                .align(Alignment.CenterEnd)
                .requiredWidth(IntrinsicSize.Min)
            , onTextLayout = {
                val width = it.size.width
                if (width > 0) {
                    val textWidthDp = with(density) { width.toDp() }
                    onChangeSize(textWidthDp)
                }
            }
        )
    }
}

And then just handle the horizontal line:

@Composable
fun CurrencyInputTextField(
    modifier: Modifier = Modifier,
    label: String
) {
    var value by remember { mutableStateOf("") }
    val focusRequester = remember { FocusRequester() }
    var isFocused by remember { mutableStateOf(false) }

    var labelWidth by remember { mutableStateOf(0.dp) }

    Box (
        modifier = modifier
            .fillMaxWidth()
            .padding(horizontal = 2.dp)
    ) {
        
        Box(
            modifier = modifier
                .fillMaxWidth()
                .padding(horizontal = 2.dp),
        ) {
            val showTopLine = (isFocused || value.isNotBlank())
            HorizontalDivider(
                thickness = if(isFocused)
                    OutlinedTextFieldDefaults.FocusedBorderThickness else
                        OutlinedTextFieldDefaults.UnfocusedBorderThickness,
                color = if(isFocused)
                    OutlinedTextFieldDefaults.colors().focusedLabelColor
                else OutlinedTextFieldDefaults.colors().unfocusedLabelColor,
                modifier = Modifier
                    .padding(horizontal = 3.dp)
                    .padding(top = 8.1.dp)
                    .alpha(if(showTopLine) 1f else 0f)
                    .fillMaxWidth()
                    .padding(end = labelWidth + 15.dp)
            )
        }
        OutlinedTextField(
            value = value,
            label = {
                TextFieldLabel(label, onChangeSize = {
                    labelWidth = it
                }) },
            prefix = { Text(text = "$") },
            onValueChange = {
                value = it
            },
            singleLine = true,
            textStyle = MaterialTheme.typography.bodyLarge.copy(textAlign = TextAlign.End),
            modifier = modifier
                .focusRequester(focusRequester)
                .onFocusChanged { focusState ->
                    isFocused = focusState.isFocused
                }
        )
    }
}

Maybe you will need to adjust some padding or color or the thickness, but this can give you an idea how can you make it.

I'm storing the label width dp in labelWidth and this is used as end padding for the horizontal line.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论