如何不依赖FocusChange检测EditText输入起止时间,计算密码输入耗时
问题分析
你现有实现的核心问题在于:
- 输入满6位直接跳转Activity时,EditText不会触发焦点丢失回调,
MyFocusChangeListener无法捕获输入结束事件 - 仅靠焦点变化计算耗时的逻辑,覆盖不了输入完成直接跳转、用户中途停止输入未切走焦点的场景
解决方案
采用超时检测机制判定输入停止,所有逻辑封装在库内无需上层适配,覆盖所有触发场景:
- 设定输入停止判定阈值(默认500ms可调整),用户连续指定时长无输入即判定为输入停止
- 每次用户输入字符时清空之前的延时任务,重新提交新的停止检测任务
- 额外处理满6位直接跳转的场景,输入到6位时直接触发结束计算,无需等超时
实现代码
1. 改造MyTextWatcher
class MyTextWatcher(private val view: EditText) : TextWatcher { // 输入停止判定超时时间,单位ms,可按需调整 private val inputStopDelay = 500L var startTypingTime: Long = 0L var lastInputTime: Long = 0L // 输入停止执行任务 private val inputStopRunnable = Runnable { val inputCost = lastInputTime - startTypingTime // 此处添加输入停止后的处理逻辑,比如埋点上报 handleInputStop(inputCost) } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { val now = System.currentTimeMillis() // 首次输入记录开始时间 if (startTypingTime == 0L) { startTypingTime = now } lastInputTime = now // 移除之前的延时任务 view.removeCallbacks(inputStopRunnable) // 输入满6位直接触发停止,无需等待超时 if (s?.length == 6) { val inputCost = lastInputTime - startTypingTime handleInputStop(inputCost) return } // 提交新的延时任务 view.postDelayed(inputStopRunnable, inputStopDelay) } override fun afterTextChanged(s: Editable?) {} private fun handleInputStop(costTimeMs: Long) { // 你的自定义处理逻辑 } // 对外暴露清理方法,避免内存泄露 fun clearTask() { view.removeCallbacks(inputStopRunnable) } }
2. 改造焦点监听逻辑
fun MyFocusChangeListener(view: View, hasFocus: Boolean) { if (!hasFocus && view is EditText) { // 失去焦点时直接触发输入停止计算 val watcher = view.getTag(R.id.tag_text_watcher) as? MyTextWatcher ?: return watcher.clearTask() if (watcher.startTypingTime != 0L && watcher.lastInputTime != 0L) { val inputCost = watcher.lastInputTime - watcher.startTypingTime // 调用处理逻辑 } } }
3. 绑定逻辑调整
首先在res/values/ids.xml中添加自定义id,用于存储Watcher实例:
<item type="id" name="tag_text_watcher" />
在Activity初始化时绑定:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ...原有逻辑不变 val myTextWatcher = MyTextWatcher(password) password.addTextChangedListener(myTextWatcher) // 将watcher实例存在Tag中 password.setTag(R.id.tag_text_watcher, myTextWatcher) password.setOnFocusChangeListener { v, hasFocus -> MyFocusChangeListener(v, hasFocus) } }
注意事项
- 超时阈值可根据业务需求调整,300-1000ms都是合理范围
- 可监听EditText的
OnAttachStateChangeListener,在View销毁时调用clearTask()避免内存泄露 - 所有逻辑均封装在库内,上层应用无需做额外适配
内容的提问来源于stack exchange,提问作者Neco
相关产品推荐
相关产品推荐

