Android EditText 光标与软键盘避坑:windowSoftInputMode 配置与 TaoToken 统一 Key 接入

发布时间:2026/9/26 17:28:12
Android EditText 光标与软键盘避坑:windowSoftInputMode 配置与 TaoToken 统一 Key 接入 1. 输入框体验崩坏现场光标乱跳、键盘顶飞布局做 Android 表单页时EditText 的输入体验问题几乎人人踩过点击输入框光标跑到文字中间、软键盘弹出把底部按钮顶出屏幕、windowSoftInputMode明明配了adjustResize却毫无反应、Dialog 里的输入框键盘死活不弹。这些问题单看都不致命但叠在一起就是用户直接卸载的理由。我试过在一个登录页里同时遇到三种情况账号框光标错位、密码框被键盘遮住、验证码按钮被顶到状态栏外面。排查下来发现根因分散在三个地方——XML 属性、Manifest 配置、以及代码里手动控制键盘的逻辑互相打架。这篇聚焦三件事第一把 EditText 光标相关的属性讲清楚包括cursorVisible、textCursorDrawable和父布局焦点配合第二把windowSoftInputMode的九种取值按实际场景拆开给出可直接复制的 AndroidManifest 片段第三给出一套用 TaoToken 统一 Key 接入 AI 能力的最小骨架方便你在输入框场景里接上智能补全、内容校验这类功能不用每个项目重新配一遍密钥。适合谁看正在做 Android 表单、聊天输入、搜索框的开发者尤其是被软键盘和光标问题反复折磨的同学。2. 前置准备TaoToken 统一 Key 与项目环境在动手改配置之前先把 AI 接入这条线铺好。TaoToken 的作用是提供一个统一的 API 通道你只需要一个 Key就能在 Android 项目里调用模型对话能力不用为每个模型单独申请账号、单独管理密钥。官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 地址https://taotoken.net/api你需要准备的东西一个 TaoToken 账号在控制台创建一个 API KeyAndroid 项目里能发网络请求OkHttp 或 Retrofit 都行本地能跑 adb 命令用来验证键盘和光标行为创建 Key 的路径登录后进控制台找到 API Keys 页面新建一个 Key 并复制保存。这个 Key 后面会写进项目的settings.json或config.toml里作为统一凭证。注意Key 不要硬编码在 Java/Kotlin 源码里放到构建配置或本地配置文件通过 BuildConfig 注入。控制台地址https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI Keys 管理页https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content3. 可复制配置AndroidManifest 与光标属性3.1 windowSoftInputMode 九种取值对照先把最核心的配置项列清楚。windowSoftInputMode写在activity标签里控制软键盘的显示状态和窗口调整方式。它由两部分组成状态部分state和调整部分adjust用竖线拼接。取值含义适用场景stateUnspecified系统自行决定不推荐行为不确定stateUnchanged保持上一个 Activity 的键盘状态连续输入页stateHidden进入时键盘隐藏详情页、展示页stateAlwaysHidden主窗口获焦时键盘始终隐藏带输入框但不想自动弹stateVisible键盘通常可见搜索页自动聚焦stateAlwaysVisible进入时键盘总是显示强制输入场景adjustUnspecified系统决定调整方式默认容易出问题adjustResize调整窗口大小留出键盘空间表单页首选adjustPan整体上移焦点不被遮挡输入框在底部时实际项目里最常用的是stateHidden|adjustResize和stateVisible|adjustPan两种组合。前者适合表单页进入时不弹键盘弹出时压缩布局后者适合聊天页进入就弹键盘内容整体上移。3.2 AndroidManifest 配置片段activity android:name.ui.LoginActivity android:windowSoftInputModestateHidden|adjustResize android:exportedfalse / activity android:name.ui.ChatActivity android:windowSoftInputModestateVisible|adjustPan android:exportedfalse / activity android:name.ui.SearchActivity android:windowSoftInputModestateAlwaysVisible|adjustResize android:exportedtrue intent-filter action android:nameandroid.intent.action.SEARCH / /intent-filter /activity3.3 EditText 光标属性配置光标问题大多出在 XML 属性没配对。下面这段可以直接抄EditText android:idid/et_input android:layout_widthmatch_parent android:layout_heightwrap_content android:cursorVisibletrue android:textCursorDrawablenull android:inputTypetext android:focusabletrue android:focusableInTouchModetrue android:paddingStart12dp android:paddingEnd12dp /cursorVisiblefalse会让光标彻底不显示即使点击也不出现textCursorDrawablenull让光标颜色跟随文字颜色避免默认主题下光标和背景对比度太低看不见。如果想让光标默认隐藏、点击时才出现把cursorVisible设为false然后在父布局加focusabletrue和focusableInTouchModetrue这样点击输入框时焦点转移光标自然出现。3.4 TaoToken 接入骨架settings.json 与 config.toml在项目根目录或模块目录放一份配置文件把 TaoToken 的 Key 和 API 地址统一管理。settings.json示例{ taotoken: { api_base: https://taotoken.net/api, api_key: sk-your-key-here, model: claude-sonnet, timeout_ms: 30000 }, input_assist: { enable_smart_complete: true, enable_content_check: true } }config.toml示例如果你用 Gradle 插件读取[taotoken] api_base https://taotoken.net/api api_key sk-your-key-here model claude-sonnet timeout_ms 30000 [input_assist] enable_smart_complete true enable_content_check trueKotlin 侧读取配置并发请求的骨架data class TaoTokenConfig( val apiBase: String, val apiKey: String, val model: String, val timeoutMs: Long ) object TaoTokenClient { private val client OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build() fun chat(config: TaoTokenConfig, prompt: String): String { val json JSONObject().apply { put(model, config.model) put(messages, JSONArray().put( JSONObject().apply { put(role, user) put(content, prompt) } )) } val body json.toString() .toRequestBody(application/json.toMediaType()) val request Request.Builder() .url(${config.apiBase}/v1/chat/completions) .addHeader(Authorization, Bearer ${config.apiKey}) .post(body) .build() client.newCall(request).execute().use { response - return response.body?.string() ?: } } }这段代码放在输入框的文本变化监听里就能实现智能补全或内容校验。Key 从配置文件读取不写死在代码里。4. 验证请求与 adb 实测动作4.1 验证 TaoToken 通道是否通先用 curl 确认 Key 和 API 地址没问题curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-your-key-here \ -H Content-Type: application/json \ -d { model: claude-sonnet, messages: [{role: user, content: ping}] }返回里带choices字段就说明通道正常。如果返回 401检查 Key 是否复制完整返回 404检查 API 路径是否拼错。4.2 adb 验证软键盘与光标行为配置改完后用 adb 直接观察键盘状态和窗口变化# 查看当前 Activity 的 windowSoftInputMode adb shell dumpsys window | grep -i softInputMode # 查看当前焦点窗口和输入法状态 adb shell dumpsys input_method | grep -i mInputShown # 模拟点击输入框观察键盘是否弹出 adb shell input tap 540 1200 # 查看窗口尺寸变化验证 adjustResize 是否生效 adb shell dumpsys window | grep -i mFrameadjustResize生效时你会看到窗口高度在键盘弹出后变小adjustPan生效时窗口高度不变但内容整体上移。如果两者都没变化说明配置没被读取检查 Manifest 里是否写在了正确的 Activity 上。4.3 光标位置验证# 查看 EditText 的 selection 位置 adb shell dumpsys activity top | grep -i selection如果点击后 selection 始终为 0 或异常值检查inputType是否设置正确以及是否有代码在onClick里手动调用了setSelection。5. 本篇常见错排查5.1 adjustResize 不生效最常见的原因是 Activity 用了全屏主题或windowTranslucentStatus导致窗口不响应键盘调整。解决办法是把主题换成非全屏或者在根布局用fitsSystemWindowstrue。另一个原因是根布局用了ScrollView且高度写死键盘弹出时没有可压缩空间。把ScrollView的layout_height改成match_parent内部内容用wrap_content。5.2 Dialog 里键盘不弹Dialog 的窗口属性和 Activity 不同需要在onCreate里手动设置override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog super.onCreateDialog(savedInstanceState) dialog.window?.setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE or WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE ) return dialog }如果还是不弹加一个 350ms 的延时再调toggleSoftInput因为 Dialog 动画未结束时请求焦点会被系统忽略。5.3 光标颜色看不见默认主题下光标颜色可能和背景接近。用textCursorDrawablenull让光标跟随文字颜色或者在主题里自定义colorControlActivated。5.4 点击输入框光标跳到文字开头通常是inputType和gravity不匹配或者代码里在onFocusChange里调了setSelection(0)。检查有没有在TextWatcher里重置文本导致光标归零。5.5 TaoToken 请求超时Android 默认不允许明文 HTTP但 TaoToken 走的是 HTTPS一般不会触发。如果超时检查OkHttpClient的connectTimeout和readTimeout是否设得太短以及设备网络是否正常。另外确认api_base没有多余斜杠正确写法是https://taotoken.net/api请求路径拼/v1/chat/completions。6. 接入文档与后续动作配置改完、adb 验证通过后下一步是把 TaoToken 的 Key 管理规范化。如果你只是临时测试直接在控制台建一个 Key 就行如果要在多个项目里复用建议按项目建不同的 Key方便追踪用量和随时吊销。API Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content如果你要在输入框场景里做长期编码辅助比如智能补全、语法检查、内容改写可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content想先验证模型对话效果直接进模型对话页试https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content最后补一个实操细节windowSoftInputMode的调整部分和状态部分用竖线拼接时顺序不影响结果但建议状态在前、调整在后可读性更好。改完 Manifest 记得 clean build有时候增量编译不会重新合并 Manifest导致配置看起来没生效。