首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Jetpack组合中输入文本OutlinedTextField的可调性

Jetpack组合中输入文本OutlinedTextField的可调性
EN

Stack Overflow用户
提问于 2022-02-10 21:33:52
回答 1查看 1.5K关注 0票数 2

我有一个带有OutlinedTextField的DropdownMenu,我希望在按下DropdownMenu列表中的项之后,项目的值开始在OutlinedTextField中,并根据文本的长度来调整其宽度。我怎么能做到呢?

更新(14.02.2022)

默认情况下,OutlinedTextField使用OutlinedTextFieldLayout,其中包含带有defaultMinSize修饰符参数的BasicTextField

代码语言:javascript
运行
复制
BasicTextField(
    value = value,
    modifier = modifier
        .then(
            if (decoratedLabel != null) {
                Modifier.padding(top = OutlinedTextFieldTopPadding)
            } else {
                Modifier
            }
        )
        .defaultMinSize(
            minWidth = MinWidth,
            minHeight = MinHeight
        )
...

 /** The default min width applied for a TextField and OutlinedTextField. Note that you can override it by applying Modifier.widthIn directly on a text field. */
 val MinWidth = 280.dp

要使宽度成为内在的Min,我必须从Compose库中复制3个文件(TextField.kt、TextFieldImpl.kt、OutlinedTextField.kt),并在OutlinedTextFieldLayout组件中使用以下更改创建自己的OutlinedTextField:

代码语言:javascript
运行
复制
 @Composable
internal fun OutlinedFormTextFieldLayout(
    modifier: Modifier,
    value: TextFieldValue,
    onValueChange: (TextFieldValue) -> Unit,
    enabled: Boolean,
    readOnly: Boolean,
    keyboardOptions: KeyboardOptions,
    keyboardActions: KeyboardActions,
    textStyle: TextStyle,
    singleLine: Boolean,
    maxLines: Int = Int.MAX_VALUE,
    visualTransformation: VisualTransformation,
    interactionSource: MutableInteractionSource,
    decoratedPlaceholder: @Composable ((Modifier) -> Unit)?,
    decoratedLabel: @Composable (() -> Unit)?,
    leading: @Composable (() -> Unit)?,
    trailing: @Composable (() -> Unit)?,
    leadingColor: Color,
    trailingColor: Color,
    labelProgress: Float,
    indicatorWidth: Dp,
    indicatorColor: Color,
    cursorColor: Color,
    shape: Shape
) {
    val textWidth = remember { mutableStateOf(0) }
    val labelSize = remember { mutableStateOf(Size.Zero) }

    fun Modifier.widthIntrinsicSizeMinModifier() = width(IntrinsicSize.Min)
    fun Modifier.widthTextWidthModifier() = width(textWidth.value.dp)

    if (textWidth.value == 0) {
        modifier.then(Modifier.widthIntrinsicSizeMinModifier())
    } else {
        modifier.then(Modifier.widthTextWidthModifier())
    }

    BasicTextField(
        value = value,
        modifier = modifier
            .then(
                if (decoratedLabel != null) {
                    Modifier.padding(top = OutlinedTextFieldTopPadding)
                } else {
                    Modifier
                }
            )
            .onSizeChanged {
                textWidth.value = it.width
            }, ...

通过这些更改,我们不再有默认宽度了,但是我们仍然有一些来自右侧的间距

Update(15.02.2022)

不要复制@Compose库中的文件。有些API调用不起作用。在我的例子中,textColor和背景集不适用于我的自定义OutlinedFormTextField,而对于OutlinedTextField,一切都很好:

代码语言:javascript
运行
复制
  colors = TextFieldDefaults.outlinedTextFieldColors(
       textColor = Color.Red,
       backgroundColor = backgroundColor.value
...

我还发现,与其覆盖与OutlinedTextField相关的文件,您还可以使用Row组件包装您的OutlinedTextField并在其中设置:

代码语言:javascript
运行
复制
Modifier.defaultMinSize(minWidth = 1.dp)

默认情况下,它将删除组成建议的巨大minWidth,但是标签之后的额外间距仍然存在。

有人知道怎么移除它吗?

EN

Stack Overflow用户

发布于 2022-02-22 04:10:58

这是我使用可调OutlinedTextField组件的临时解决方案。当背景被更改时,它还修复了左上角的OutlinedTextField交叉标签:

代码语言:javascript
运行
复制
// Duration
private const val LabelOffsetAnimationDuration = 500
private const val LabelBackgroundColorAnimationDuration = 1

private const val LabelBackgroundColorAnimationDelay = 200

private const val TextFieldBackgroundColorAnimationDuration = 0
private const val TextFieldBackgroundColorAnimationDelay = 0

private const val BorderColorAnimationDuration = 10
private const val BorderColorAnimationDelay = 50

// Offset
private const val LabelAnimationTopLeftPositionOffsetX = 20F
private const val LabelAnimationTopLeftPositionOffsetY = -30F
private const val LabelAnimationCenterPositionOffsetX = 25F
private const val LabelAnimationCenterPositionOffsetY = 0F

private const val LabelTextSizeAnimationTopLeftPosition = 12F
private const val LabelTextSizeAnimationCenterPosition = 16F

// Z-Index
private const val LabelBubbleZIndex = 2f

// Size
private val TextFieldMinWidth = 100.dp

private fun getTargetLabelPosition(isFocused: Boolean, text: String) =
 if (!isFocused && text.isNotEmpty() || isFocused) {
     LabelPosition.TopLeft
 } else {
     LabelPosition.Center
 }

@Composable
fun MyOutlinedTextField(
    modifier: Modifier = Modifier,
    textFieldState: TextFieldState,
    onValueChange: (String) -> Unit,
    label: String,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    isError: Boolean,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardAction: ((KeyboardActionScope) -> Unit),
    trailingIcon: @Composable (() -> Unit)? = null,
) {
    Column(
        modifier = modifier,
        verticalArrangement = Arrangement.Center
    ) {
        var textFieldIsFocused by remember { mutableStateOf(false) }
        var labelPosition by remember {
            mutableStateOf(
                getTargetLabelPosition(
                    isFocused = textFieldIsFocused,
                    text = textFieldState.text
                )
            )
        }

        val labelPositionTransition = updateTransition(
            targetState = labelPosition,
            label = LabelPositionTransitionLabel
        )

        val labelOffsetAnimation by labelPositionTransition.animateOffset(
            transitionSpec = {
                tween(
                    durationMillis = LabelOffsetAnimationDuration
                )
            },
            label = LabelOffsetAnimationLabel
        ) { position ->
            when (position) {
                LabelPosition.TopLeft -> Offset(
                    LabelAnimationTopLeftPositionOffsetX,
                    LabelAnimationTopLeftPositionOffsetY
                )
                LabelPosition.Center -> Offset(
                    LabelAnimationCenterPositionOffsetX,
                    LabelAnimationCenterPositionOffsetY
                )
            }
        }

        val labelTextSizeAnimation by labelPositionTransition.animateFloat(
            label = LabelTextSizeAnimationLabel
        ) { position ->
            when (position) {
                LabelPosition.TopLeft -> LabelTextSizeAnimationTopLeftPosition
                LabelPosition.Center -> LabelTextSizeAnimationCenterPosition
            }
        }

        val labelBackgroundColorAnimation by labelPositionTransition.animateColor(
            transitionSpec = {
                tween(
                    durationMillis = LabelBackgroundColorAnimationDuration,
                    delayMillis = LabelBackgroundColorAnimationDelay,
                )
            },
            label = LabelBackgroundColorAnimationLabel
        ) { position ->
            when (position) {
                LabelPosition.TopLeft -> Color.White
                LabelPosition.Center -> Color.Transparent
            }
        }

        val textFieldIsFocusedTransition = updateTransition(
            targetState = textFieldIsFocused,
            label = TextFieldIsFocusedTransitionLabel
        )

        val textFieldBackgroundColorAnimation by textFieldIsFocusedTransition.animateColor(
            transitionSpec = { ->
                tween(
                    durationMillis = TextFieldBackgroundColorAnimationDuration,
                    delayMillis = TextFieldBackgroundColorAnimationDelay,
                )
            },
            label = TextFieldBackgroundColorAnimationLabel
        ) { _isFocused ->
            when {
                _isFocused -> LinkWater
                !_isFocused && textFieldState.text.isEmpty() -> Color.Transparent
                !_isFocused && textFieldState.text.isNotEmpty() -> Alabaster
                else -> Color.Transparent
            }
        }

        val borderColorAnimation by textFieldIsFocusedTransition.animateColor(
            transitionSpec = { ->
                tween(
                    durationMillis = BorderColorAnimationDuration,
                    delayMillis = BorderColorAnimationDelay,
                )
            },
            label = BorderColorAnimationLabel
        ) { _isFocused ->
            when {
                _isFocused -> Color.Transparent
                !_isFocused && textFieldState.text.isEmpty() -> Mercury
                !_isFocused && textFieldState.text.isNotEmpty() -> Color.Transparent
                else -> Mercury
            }
        }

        val textFieldBoxModifier = Modifier.textFieldBoxModifier(
            textFieldState = textFieldState,
            textFieldBackgroundColorAnimation = textFieldBackgroundColorAnimation,
            borderColorAnimation = borderColorAnimation,
            textFieldIsFocused = textFieldIsFocused
        )

        Box(
            contentAlignment = Alignment.CenterStart
        ) {
            Text(
                modifier = Modifier
                    .zIndex(LabelBubbleZIndex)
                    .defaultMinSize(1.dp)
                    .offset(labelOffsetAnimation.x.dp, labelOffsetAnimation.y.dp)
                    .clip(
                        shape = CircleShape
                    )
                    .background(
                        color = labelBackgroundColorAnimation
                    )
                    // Padding inside the Email bubble
                    .padding(
                        start = if (labelPosition == LabelPosition.TopLeft) 8.dp else 0.dp,
                        end = if (labelPosition == LabelPosition.TopLeft) 8.dp else 0.dp,
                        top = 2.dp,
                        bottom = 2.dp
                    ),
                text = label,
                fontSize = dpToSp(
                    labelTextSizeAnimation,
                    LocalContext.current
                ).sp,
                style = LocalTextStyle.current.copy(
                    color = OsloGray
                ),
            )

            Box(
                modifier = textFieldBoxModifier
            ) {
                TextField(
                    modifier = Modifier
                        .padding(
                            start = 8.dp,
                            end = 8.dp
                        )
                        .onFocusChanged {
                            textFieldIsFocused = it.isFocused
                            labelPosition =
                                getTargetLabelPosition(textFieldIsFocused, textFieldState.text)
                            textFieldState.enableDisplayErrors(textFieldIsFocused)
                        }
                        .defaultMinSize(
                            minWidth = 1.dp
                        ),
                    value = textFieldState.text,
                    onValueChange = onValueChange,
                    enabled = enabled,
                    keyboardOptions = keyboardOptions,
                    readOnly = readOnly,
                    isError = isError,
                    keyboardActions = KeyboardActions(
                        keyboardAction
                    ),
                    trailingIcon = trailingIcon,
                    singleLine = true,
                    textStyle = TextFieldStyle,
                    colors = TextFieldDefaults.textFieldColors(
                        textColor = Fiord,
                        cursorColor = Fiord,
                        disabledTextColor = Color.Transparent,
                        backgroundColor = Color.Transparent,
                        focusedIndicatorColor = Color.Transparent,
                        unfocusedIndicatorColor = Color.Transparent,
                        disabledIndicatorColor = Color.Transparent,
                        errorIndicatorColor = Color.Transparent
                    )
                )
            }
        }
        textFieldState.getError()?.let { error ->
            TextFieldError(
                textError = error
            )
        }
    }
}

private fun Modifier.textFieldBoxModifier(
    textFieldState: TextFieldState,
    textFieldBackgroundColorAnimation: Color,
    borderColorAnimation: Color,
    textFieldIsFocused: Boolean
): Modifier {
    var basicTextFieldBoxModifier = this
        .padding(
            start = 4.dp,
            end = 4.dp,
            top = 8.dp,
            bottom = 8.dp
        )
        .height(60.dp)
        .background(
            color = textFieldBackgroundColorAnimation,
            shape = CircleShape
        )
        .border(1.dp, borderColorAnimation, CircleShape)
        .zIndex(1f)
        .wrapContentSize(
            align = Alignment.CenterStart
        )

    when {
        textFieldIsFocused -> {
            basicTextFieldBoxModifier = basicTextFieldBoxModifier.then(Modifier.fillMaxWidth())
        }
        !textFieldIsFocused && textFieldState.text.isEmpty() -> {
            basicTextFieldBoxModifier =
                basicTextFieldBoxModifier.then(Modifier.width(TextFieldMinWidth))
        }
    }

    return basicTextFieldBoxModifier
}
票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71072553

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档