如何监听TextView文本选择完成(选择菜单弹出时刻)的事件?
可行实现方案
方案1:防抖过滤连续回调(兼容全版本)
onPrepareActionMode在拖动手柄时的连续触发属于高频临时回调,松手菜单弹出后只会触发最后一次,因此可以通过延迟防抖的方式过滤掉无效回调:
- 定义主线程Handler和延迟任务,每次触发
onPrepareActionMode时先移除未执行的延迟任务,再重新提交新的延迟任务 - 延迟时长设置为100~200ms即可,该时长既可以过滤掉拖动过程中的连续触发,用户也感知不到明显滞后
- 在
onDestroyActionMode中移除未执行的任务,避免内存泄漏和错误触发
对应代码示例:
private val actionModeHandler = Handler(Looper.getMainLooper()) private var menuShowTask: Runnable? = null val callback = object: ActionMode.Callback{ @SuppressLint("ResourceType") override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean { Log.d("test", "onCreateActionMode"); return true; } override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean { Log.d("test", "onPrepareActionMode") // 先移除之前的未执行任务 menuShowTask?.let { actionModeHandler.removeCallbacks(it) } // 提交新的延迟任务,延迟150ms执行 menuShowTask = Runnable { // 此处就是菜单弹出、选择完成的回调时机,执行你需要的逻辑 Log.d("test", "选择菜单已弹出,选择完成") }.also { actionModeHandler.postDelayed(it, 150) } return false } override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { Log.d("test", "onActionItemClicked"); return false; } override fun onDestroyActionMode(mode: ActionMode?) { Log.d("test", "onDestroyActionMode") // 销毁时移除任务 menuShowTask?.let { actionModeHandler.removeCallbacks(it) } menuShowTask = null } };
方案2:API 29+ 专用方案
如果你的App最低支持版本为Android 10(API 29),可以直接使用TextView提供的setOnSelectionChangedListener,配合判断ActionMode是否存在即可:
textView.setOnSelectionChangedListener { selStart, selEnd -> // 有选中范围,且当前存在ActionMode时,说明选择完成、菜单弹出 if (selStart != selEnd && textView.customSelectionActionModeCallback != null) { // 执行你的逻辑 } }
内容的提问来源于stack exchange,提问作者Damn Vegetables
相关产品推荐
相关产品推荐

