当前位置: 首页 > article >正文

Android CustomTextField

在 Compose 中开发用户界面时,需要处理输入框和键盘的交互,例如在键盘弹出时调整布局位置,避免遮挡重要内容。本篇博客将通过一个完整的示例展示如何实现这一功能。

功能概述

本例实现了一个简单的输入框。当输入框获得焦点或输入文字时,以下行为发生:

  1. 键盘弹出。

  2. 输入框上方的占位符文本根据焦点状态和输入内容动态显示或隐藏。

  3. 整个布局根据键盘的弹出状态自动调整,避免内容被遮挡。

代码实现

封装TextField代码:
@Composable
fun CustomTextField(placeholderText: String, imageVector: Any) {
    // 定义状态变量管理输入框的文本和焦点状态
    var textValue by remember { mutableStateOf("") }
    var isTextFieldFocused by remember { mutableStateOf(false) }

    // 获取焦点管理器和键盘控制器
    val focusManager = LocalFocusManager.current
    val keyboardController = LocalSoftwareKeyboardController.current

    // 动态计算底部间距,键盘弹出时调整布局
    val bottomPadding by animateDpAsState(
        targetValue = if (isTextFieldFocused || textValue.isNotEmpty()) 40.dp else 16.dp
    )

    // 使用 Box 包裹输入框和占位符文本
    Box {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .height(70.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Bottom
        ) {
            // 输入框组件
            Row(
                modifier = Modifier
                    .border(1.dp, Color.Black, RoundedCornerShape(16.dp))
                    .clip(RoundedCornerShape(16.dp))
                    .padding(0.dp) // 确保内边距为 0,避免额外的间距
            ) {
                // 在 TextField 前添加图标,根据传入的 imageVector 参数显示不同图标
                Icon(
                    imageVector = imageVector as androidx.compose.ui.graphics.vector.ImageVector,
                    contentDescription = "Icon",
                    modifier = Modifier
                        .size(35.dp)
                        .padding(
                            start = 10.dp,
                            top = 15.dp,
                            end = 0.dp,
                            bottom = 0.dp
                        )
                )

                TextField(
                    value = textValue,
                    onValueChange = { newText ->
                        textValue = newText
                    },
                    modifier = Modifier
                        .width(300.dp)
                        .height(50.dp)
                        .onFocusChanged { focusState ->
                            isTextFieldFocused = focusState.isFocused
                        },
                    keyboardOptions = KeyboardOptions.Default.copy(
                        imeAction = ImeAction.Done
                    ),
                    keyboardActions = KeyboardActions(
                        onDone = {
                            isTextFieldFocused = false
                            focusManager.clearFocus()
                        }
                    )
                )
            }
        }

        Column(
            modifier = Modifier
                .fillMaxWidth()
                .height(70.dp),
            horizontalAlignment = Alignment.Start,
            verticalArrangement = Arrangement.Bottom
        ) {
            // 占位符文本
            Text(
                text = placeholderText,
                modifier = Modifier
                    .padding(
                        start = 40.dp,
                        top = 0.dp,
                        end = 0.dp,
                        bottom = bottomPadding
                    )
                    .background(Color(235, 226, 241)),
                color = Color.Gray
            )
        }
    }
}

界面逻辑代码:

@Composable
fun BoxAlignmentExample() {
    // 设置 Surface 作为背景容器,填充整个屏幕
    Surface(
        modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight(),
        color = Color(235, 226, 241)
    ) {
        // 使用 Column 布局排列内容
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Top
        ) {
            // name
            CustomTextField(placeholderText = " 请输入账号 ", imageVector = Icons.Default.Person)

            // password
            CustomTextField(placeholderText = " 请输入密码 ", imageVector = Icons.Default.Lock)
        }
    }
}

核心实现

  1. 状态管理 使用 remember 和 mutableStateOf 管理输入框文本内容 (textValue) 和焦点状态 (isTextFieldFocused)。

  2. 动画效果 借助 animateDpAsState 动态调整布局底部间距 bottomPadding,为界面变化提供平滑过渡。

  3. 输入框的焦点处理

    • 使用 onFocusChanged 检测输入框的焦点状态,更新 isTextFieldFocused

    • 在键盘输入完成时,通过 focusManager.clearFocus() 和 keyboardController?.hide() 收起键盘。

  4. 占位符文本逻辑

    • 如果输入框内容为空且未聚焦,显示占位符。

    • 根据状态动态调整占位符的显示位置和样式。


http://www.kler.cn/a/510902.html

相关文章:

  • VIVADO FIFO (同步和异步) IP 核详细使用配置步骤
  • CSS 合法颜色值
  • “libcudart,so.1 1.0“ loss解决方案
  • VUE3 vite下的axios跨域
  • 记录 idea 启动 tomcat 控制台输出乱码问题解决
  • RV1126+FFMPEG推流项目(9)AI和AENC模块绑定,并且开启线程采集
  • 【2024年华为OD机试】(B卷,200分)- 学生方阵 (Java JS PythonC/C++)
  • Docker使用 使用Dockerfile来创建镜像
  • 【论文阅读】VCD-FL: Verifiable, collusion-resistant, and dynamic federated learning
  • python如何解析word文件格式(.docx)
  • 每日一题 405. 数字转换为十六进制数
  • .NET周刊【1月第1期 2025-01-05】
  • 如何优化爬虫以提高效率
  • vue 基础一
  • SSM基于微信小程序智慧农产品系统
  • ES6都有什么
  • K8S的探针说明和使用方式
  • RabbitMQ高级特性之发送方确认
  • 类和对象(3)——继承:extends关键字、super关键字、protected关键字、final关键字
  • SLAM 6 3Dto2D 的Pnp 和光束平移法
  • 医院挂号就诊系统设计与实现(代码+数据库+LW)
  • 红黑树封装map和set(c++版)
  • Vue3:当v-if和v-for同时使用时产生的问题和解决办法
  • AI Agent的总体概念:感知,记忆,规划,外部工具,执行
  • PTA乙级1001~1005【c++】
  • 线段树优化dp,abc389F - Rated Range