Compose-自定义输入框(BasicTextField)

本文档展示了如何在Jetpack Compose中自定义BasicTextField,添加左侧图标、右侧删除按钮以及hint功能。提供了完整的自定义组件代码,并给出了实际使用示例,包括手机号和验证码输入框。此外,还提供了一个仅包含hint的多行输入框实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

Compose 中的 TextField()material 风格的输入框, 只得把 BasicTextField 自定义一下。
BasicTextField 的参数这里就不介绍了, 网上介绍的文章已经不少了.

先上图:
在这里插入图片描述
自定义的内容有:

  1. 左侧的小图标
  2. 右侧的删除按钮
  3. hint 空字符时的提示

一、上代码

/**
 * @param hint: 空字符时的提示
 * @param startIcon: 左侧图标;  -1 则不显示
 * @param iconSpacing: 左侧图标与文字的距离; 相当于: drawablePadding
 */
@Composable
fun CustomEdit(
  text: String = "",
  onValueChange: (String) -> Unit,
  modifier: Modifier,
  hint: String = "请输入",
  @DrawableRes startIcon: Int = -1,
  iconSpacing: Dp = 6.dp,

  enabled: Boolean = true,
  readOnly: Boolean = false,
  textStyle: TextStyle = TextStyle.Default,
  keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
  keyboardActions: KeyboardActions = KeyboardActions.Default,
  visualTransformation: VisualTransformation = VisualTransformation.None,
  cursorBrush: Brush = SolidColor(MaterialTheme.colors.primary)
) {
  // 焦点, 用于控制是否显示 右侧叉号
  var hasFocus by remember { mutableStateOf(false) }

  BasicTextField(
    value = text,
    onValueChange = onValueChange,
    modifier = modifier.onFocusChanged { hasFocus = it.isFocused },
    singleLine = true,
    enabled = enabled,
    readOnly = readOnly,
    textStyle = textStyle,
    keyboardOptions = keyboardOptions,
    keyboardActions = keyboardActions,
    visualTransformation = visualTransformation,
    cursorBrush = cursorBrush,
    decorationBox = @Composable { innerTextField ->
      Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically
      ) {
        // -1 不显示 左侧Icon
        if(startIcon != -1){
          Image(painter = painterResource(id = startIcon), contentDescription = null)
          Spacer(modifier = Modifier.width(iconSpacing))
        }

        Box(modifier = Modifier.weight(1f)){
          // 当空字符时, 显示hint
          if(text.isEmpty())
            Text(text = hint, color = GrayAa, style = textStyle)

          // 原本输入框的内容
          innerTextField()
        }

        // 存在焦点 且 有输入内容时. 显示叉号
        if(hasFocus && text.isNotEmpty()) {
          Image(imageVector = Icons.Filled.Clear, // 清除图标
            contentDescription = null,
            // 点击就清空text
            modifier = Modifier.clickable { onValueChange.invoke("") })
        }
      }
    }
  )
}

二、使用

// vm : ViewModel; 
// 手机号输入框
CustomEdit(
  text = vm.phone,
  onValueChange = {
    vm.phone = it
  },
  modifier = Modifier
    .fillMaxWidth()
    .padding(start = 16.dp, top = 20.dp, end = 16.dp)
    .height(50.dp)
    .background(GrayE5, shape = MaterialTheme.shapes.medium)
    .padding(horizontal = 16.dp),
  hint = "请输入手机号",
  startIcon = R.drawable.ic_login_phone,
  iconSpacing = 16.dp,
  textStyle = Typography.body1,
  // keyboardType -> 半个 inputType; 这里是 Phone
  keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone),
)

// code 输入框
CustomEdit(
  text = vm.code,
  onValueChange = {
    vm.code = it
  },
  modifier = Modifier
    .fillMaxSize()
    .background(GrayE5, shape = MaterialTheme.shapes.medium)
    .padding(horizontal = 16.dp),
  hint = "请输入验证码",
  startIcon = R.drawable.ic_login_pwd,
  iconSpacing = 16.dp,
  textStyle = Typography.body1,
  keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
)

三、只有hint的 BasicTextField

1. 自定义CustomEditHint

/**
 * 只增加 hint;  适合多行输入框, 没有前后Icon的小输入框; 背景 尺寸等 定义在modifier中;
 * @param hint: 空字符时的提示
 */
@Composable
fun CustomEditHint(
  text: String = "",
  onValueChange: (String) -> Unit,
  modifier: Modifier,
  hint: String = "请输入",

  enabled: Boolean = true,
  readOnly: Boolean = false,
  singleLine: Boolean = false,
  textStyle: TextStyle = TextStyle.Default,
  keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
  keyboardActions: KeyboardActions = KeyboardActions.Default,
  visualTransformation: VisualTransformation = VisualTransformation.None,
  cursorBrush: Brush = SolidColor(MaterialTheme.colors.primary)
) {
  // 焦点, 用于控制是否显示 右侧叉号
  BasicTextField(
    value = text,
    onValueChange = onValueChange,
    modifier = modifier,
    singleLine = singleLine,
    enabled = enabled,
    readOnly = readOnly,
    textStyle = textStyle,
    keyboardOptions = keyboardOptions,
    keyboardActions = keyboardActions,
    visualTransformation = visualTransformation,
    cursorBrush = cursorBrush,
    decorationBox = @Composable { innerTextField ->
      if(text.isEmpty())
        Text(text = hint, color = GrayAa, style = textStyle)
      innerTextField()
    }
  )
}

2.Preview

@Preview(showBackground = true)
@Composable
fun TextFieldViewPreview() {
  val scrollState = rememberScrollState()
  Column(
    modifier = Modifier.verticalScroll(scrollState)
  ) {
    var text by remember { mutableStateOf("") }
	// 带前icon 及 后清除icon 的输入框
    CustomEdit(
      text = text,
      onValueChange = {
        text = it.trim()
      },
      modifier = Modifier
        .fillMaxWidth()
        .padding(start = 16.dp, top = 20.dp, end = 16.dp)
        .height(50.dp)
        .background(GrayE5, shape = MaterialTheme.shapes.medium)
        .padding(horizontal = 16.dp),
      hint = "请输入手机号",
      iconSpacing = 16.dp,
      textStyle = TextDark16,
      keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
      keyboardActions = KeyboardActions(onSearch = {
        ComApplication.INSTANCES.toast("搜索:$text")
      }),
    )

	// 多行输入框
    CustomEditHint(
      text = text,
      onValueChange = {
        text = it.trim()
      },
      modifier = Modifier
        .fillMaxWidth()
        .padding(top = 16.dp)
        .height(200.dp)
        .background(GrayE5)
        .padding(horizontal = 14.dp, vertical = 12.dp),
      hint = "请输入详情",
    )
	
	// 小输入框
    var text2 by remember { mutableStateOf("") }
    Box(
      modifier = Modifier
        .fillMaxWidth()
        .background(Color.White)
        .padding(14.dp)
    ){
      Text(text = "联系方式", style = TextDarkBlod14)

      CustomEditHint(
        text = text2,
        onValueChange = {
          text2 = it.trim().let { str ->
            // maxLength = 15
            if(str.length > 15){
              str.substring(0, 15)
            } else {
              str
            }
          }
        },
        modifier = Modifier
          .align(Alignment.CenterEnd)
          .defaultMinSize(100.dp, 14.dp),
        hint = "手机或邮箱都可以哦",
        singleLine = true,
        textStyle = TextStyle.Default.copy(textAlign = TextAlign.End)
      )
    }
  }
}

总结

没有总结!

上一篇: 记一次自定义View:滑动标尺
下一篇: Compose-navigation: 问题汇总

<think>好的,我现在要帮用户解决如何使用docker-compose -f指令启动指定的docker-compose-energy.yml文件中的服务。首先,我需要回忆一下docker-compose的基本命令结构。 用户提到了使用-f选项,所以根据Docker Compose的文档,-f是用来指定自定义compose文件的。默认情况下,docker-compose会找当前目录下的docker-compose.yml文件,但如果用户有自己的文件,比如这里的docker-compose-energy.yml,就需要用-f来指定。 接下来,我需要确认正确的命令格式。基本结构应该是docker-compose -f [文件名] up,然后可能需要加上其他选项,比如-d在后台运行。所以基础命令可能是docker-compose -f docker-compose-energy.yml up -d。这样就能启动服务并在后台运行。 然后,我需要考虑用户可能的后续需求,比如如何停止服务。这时候应该用docker-compose -f 文件名 down。还有查看日志的命令,比如docker-compose -f 文件名 logs -f。这些都是常见的使用场景,应该包含在回答里,方便用户后续操作。 另外,用户可能对docker-compose.yml文件的结构不太熟悉,或者需要检查配置是否正确。可能需要提醒他们在启动前验证文件格式是否正确,可以使用docker-compose config命令。不过用户的问题主要是启动,所以这部分可以作为补充信息。 还要注意,如果用户的环境中有多个compose文件,可能需要合并或者其他操作,但根据问题描述,用户只需要启动一个特定的文件,所以暂时不需要涉及多文件的情况。 最后,确保回答的结构清晰,先给出基础启动命令,然后列出常用操作,这样用户能一步步跟着操作。同时引用相关文档部分,比如引用中的docker-compose up -d和docker-compose down,来增强可信度。</think>根据Docker Compose的使用规范,启动指定YAML文件的服务需使用`-f`参数指定配置文件路径,具体操作步骤如下: **基础启动命令** ```bash docker-compose -f docker-compose-energy.yml up -d ``` **参数说明** - `-f`:指定自定义Compose文件路径 - `up`:创建并启动服务容器 - `-d`:以守护进程模式(后台运行) **常用扩展操作** 1. **停止并删除服务** ```bash docker-compose -f docker-compose-energy.yml down ``` 该命令会停止容器并移除网络/数据卷(除非配置了持久化卷)[^2] 2. **查看实时日志** ```bash docker-compose -f docker-compose-energy.yml logs -f ``` 3. **重建镜像并启动** ```bash docker-compose -f docker-compose-energy.yml up -d --build ``` 当修改了Dockerfile或依赖文件后需要重建镜像时使用[^3] 4. **仅验证配置文件** ```bash docker-compose -f docker-compose-energy.yml config ``` 用于检查YAML文件语法正确性,验证通过无输出[^2] **注意事项** 1. 文件路径支持相对路径和绝对路径,例如: ```bash docker-compose -f ./config/docker-compose-energy.yml up -d ``` 2. 如果文件中包含`build`指令,会优先使用本地构建的镜像而非仓库镜像[^3] 3. 端口映射冲突时会出现错误提示,需检查`ports`配置项是否与其他服务冲突[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值