繁体   English   中英

在 Jetpack Compose with Material3 的应用栏中显示文本字段

[英]Showing a text field in the app bar in Jetpack Compose with Material3

许多 Android 应用程序在应用程序栏/工具栏中都有一个搜索框,看起来有点像这个截图:

如何在 Jetpack Compose + Material3 中重新创建类似的东西? 我希望文本字段具有以下功能:

  • 支持在内容字符串为空时显示提示(例如“键入您的搜索...”)
  • 自动对焦于第一个构图,以便打开键盘
  • 将 cursor 放在第一个组合的内容字符串的末尾

我试图通过将TextField放在CenterAlignedTopAppBartitle中来重现 Jetpack Compose + Material3 中的相同行为,但结果看起来不太好。 文本字段使用了应用栏的整个高度,并具有灰色背景,这两个东西看起来都很奇怪。

经过一些工程,我想出了一个AppBarTextField ,请参见下面的代码。 我不得不使用较低级别的BasicTextField ,因为普通的TextField不够可定制。 与主题和颜色有关的代码直接从TextField的实现中复制,因此主题的自定义通常适用于文本字段的组件。

AppBarTextField可组合接受的参数是:

  • value : 要在文本字段中显示的内容字符串
  • onValueChange :在这里传递新值(记得更新value !)
  • hint :当文本字段为空时显示的提示
  • modifierkeyboardOptionskeyboardActions :它们直接传递给BasicTextField并且它们的行为与普通TextField中的行为相同。 如果您需要自定义其他TextField参数,只需将它们添加到 function 签名中,然后将它们传递给BasicTextField

实现了请求的功能:

  • 焦点获取是通过SideEffect实现的,因此它只会发生在第一个合成上
  • 将 cursor 放在使用TextFieldValue所需的第一个组合的末尾
  • 看起来奇怪的背景不再存在,因为没有.background()修饰符存在(虽然它在普通TextField中)
  • 通过在decorationBox参数中将placeholder传递给TextFieldDecorationBox来添加提示(请注意,这也可以使用TextField
  • TextFieldDecorationBox的填充现在也只有4dp 此处添加了填充(而不是在BasicTextField上使用修饰符),因为否则底线指示器(而是使用.indicatorLine()修饰符显示)将无法正确显示。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppBarTextField(
    value: String,
    onValueChange: (String) -> Unit,
    hint: String,
    modifier: Modifier = Modifier,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
) {
    val interactionSource = remember { MutableInteractionSource() }
    val textStyle = LocalTextStyle.current
    val colors = TextFieldDefaults.textFieldColors()

    // If color is not provided via the text style, use content color as a default
    val textColor = textStyle.color.takeOrElse {
        MaterialTheme.colorScheme.onSurface
    }
    val mergedTextStyle = textStyle.merge(TextStyle(color = textColor, lineHeight = 50.sp))

    // request focus when this composable is first initialized
    val focusRequester = FocusRequester()
    SideEffect {
        focusRequester.requestFocus()
    }

    // set the correct cursor position when this composable is first initialized
    var textFieldValue by remember {
        mutableStateOf(TextFieldValue(value, TextRange(value.length)))
    }
    textFieldValue = textFieldValue.copy(text = value) // make sure to keep the value updated

    CompositionLocalProvider(
        LocalTextSelectionColors provides LocalTextSelectionColors.current
    ) {
        BasicTextField(
            value = textFieldValue,
            onValueChange = {
                textFieldValue = it
                // remove newlines to avoid strange layout issues, and also because singleLine=true
                onValueChange(it.text.replace("\n", ""))
            },
            modifier = modifier
                .fillMaxWidth()
                .heightIn(32.dp)
                .indicatorLine(
                    enabled = true,
                    isError = false,
                    interactionSource = interactionSource,
                    colors = colors
                )
                .focusRequester(focusRequester),
            textStyle = mergedTextStyle,
            cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
            keyboardOptions = keyboardOptions,
            keyboardActions = keyboardActions,
            interactionSource = interactionSource,
            singleLine = true,
            decorationBox = { innerTextField ->
                // places text field with placeholder and appropriate bottom padding
                TextFieldDefaults.TextFieldDecorationBox(
                    value = value,
                    visualTransformation = VisualTransformation.None,
                    innerTextField = innerTextField,
                    placeholder = { Text(text = hint) },
                    singleLine = true,
                    enabled = true,
                    isError = false,
                    interactionSource = interactionSource,
                    colors = colors,
                    contentPadding = PaddingValues(bottom = 4.dp)
                )
            }
        )
    }
}

这是一个示例用法:

var value by rememberSaveable { mutableStateOf("initial content") }
CenterAlignedTopAppBar(
    title = {
        AppBarTextField(
            value = value,
            onValueChange = { newValue -> value = newValue },
            hint = "A hint..."
        )
    },
    navigationIcon = /* the back icon */,
    actions = /* the search icon */
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM