Webview自定义文本选择菜单(CAB)异常:部分华为设备未调用startActionMode()
解决华为设备WebView自定义文本选择菜单不触发startActionMode的问题
我之前也踩过华为设备上WebView自定义文本选择菜单的这个坑,常规重写startActionMode的方案在部分华为机型上确实会失效——它们的WebView实现把文本选择的菜单触发逻辑走了showContextMenu而非startActionMode。分享几个原生层面的简洁解决思路:
方案一:重写WebView的showContextMenu方法拦截默认菜单
既然你已经观察到选中文本时showContextMenu()会被触发,那我们直接在这里拦截默认菜单,手动启动自定义的ActionMode:
@Override public boolean showContextMenu() { // 获取当前WebView选中的文本 String selectedText = getSelectedText(); // 只有选中了文本才触发自定义菜单 if (!TextUtils.isEmpty(selectedText)) { // 启动自定义ActionMode startActionMode(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // 加载你的自定义菜单布局 mode.getMenuInflater().inflate(R.menu.webview_custom_selection_menu, menu); // 可以在这里设置ActionMode的标题,比如显示选中的文本长度 mode.setTitle(String.format("已选 %d 字", selectedText.length())); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // 不需要额外准备的话返回false即可 return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // 处理菜单点击事件 switch (item.getItemId()) { case R.id.menu_custom_copy: // 执行自定义复制逻辑 ClipboardManager clipboard = (ClipboardManager) getContext() .getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("WebView选中文本", selectedText); clipboard.setPrimaryClip(clip); Toast.makeText(getContext(), "已复制", Toast.LENGTH_SHORT).show(); mode.finish(); return true; case R.id.menu_custom_share: // 执行分享逻辑 Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); shareIntent.putExtra(Intent.EXTRA_TEXT, selectedText); getContext().startActivity(Intent.createChooser(shareIntent, "分享文本")); mode.finish(); return true; // 其他自定义菜单项的处理 default: return false; } } @Override public void onDestroyActionMode(ActionMode mode) { // 菜单销毁时的清理操作,比如清空选中状态(可选) clearFocus(); } }); // 返回true,阻止系统默认上下文菜单弹出 return true; } // 没有选中文本时,走默认逻辑 return super.showContextMenu(); }
这个方案的核心是利用华为WebView触发showContextMenu的特性,在这里直接接管菜单逻辑,完全用原生代码实现,不需要依赖JS。
补充注意事项
- 选中文本的兼容性:
getSelectedText()方法要求API 19及以上,华为设备基本都是API 19+,这个问题不大;如果需要兼容更低版本,可以考虑用evaluateJavascript执行JS获取选中文本,但你倾向原生的话可以忽略这条。 - ActionMode样式自定义:如果需要修改ActionMode的样式(比如背景色),可以在主题中设置
actionModeStyle属性,避免和系统默认样式冲突。 - 测试边界情况:比如选中部分文本、选中全部文本、没有选中文本时的表现,确保逻辑覆盖全面。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

