Android 12 type_floating类型ActionMode菜单项仅显示标题不显示图标
问题原因
Android 12(API 31)调整了浮动类型ActionMode(即TYPE_FLOATING)的菜单默认渲染规则:系统给浮动操作模式的弹出菜单默认关闭了可选图标显示开关,即使手动给MenuItem设置SHOW_AS_ACTION_ALWAYS和图标资源,系统也会默认隐藏图标仅展示文本,这也是低版本正常、Android 12异常的核心原因。
另外你贴的代码存在明显笔误:给red菜单项赋值后,后续调用setShowAsAction、setIcon的是未定义的note变量,这部分会直接触发运行时异常,优先修正。
异常效果参考:
修复方案
第一步:补全所有菜单项的基础配置
把setFloatingMenuClickListeners方法里的配置补全,给每个菜单项单独设置展示规则和对应图标,修正变量名错误:
private void setFloatingMenuClickListeners(Menu menu) { MenuItem red = menu.findItem(R.id.red_view); red.setOnMenuItemClickListener(actionModeClick); red.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); red.setIcon(R.drawable.icon_red); MenuItem orange = menu.findItem(R.id.orange_view); orange.setOnMenuItemClickListener(actionModeClick); orange.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); orange.setIcon(R.drawable.icon_orange); MenuItem pink = menu.findItem(R.id.pink_view); pink.setOnMenuItemClickListener(actionModeClick); pink.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); pink.setIcon(R.drawable.icon_pink); }
把上面的图标资源替换成你项目里实际的资源id即可。
第二步:兼容Android 12的图标隐藏逻辑
两种方案二选一即可:
方案1:反射强制开启菜单图标显示(侵入性最低)
在ActionMode创建阶段,通过反射调用菜单内部方法强制打开图标显示开关,不需要修改主题配置:
@Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { menu.clear(); mode.getMenuInflater().inflate(R.menu.menu_feature, menu); // Android 12+ 兼容处理 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { try { Method getMenuBuilder = mode.getClass().getDeclaredMethod("getMenuBuilder"); getMenuBuilder.setAccessible(true); Object menuBuilder = getMenuBuilder.invoke(mode); if (menuBuilder != null) { Method setIconsVisible = menuBuilder.getClass() .getDeclaredMethod("setOptionalIconsVisible", boolean.class); setIconsVisible.setAccessible(true); setIconsVisible.invoke(menuBuilder, true); } } catch (Exception ignored) { // 反射失败不影响核心功能,无需额外处理 } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mode.invalidateContentRect(); } setFloatingMenuClickListeners(menu); return true; }
把原来写在onActionModeStarted里的菜单初始化逻辑挪到onCreateActionMode里,避免系统提前渲染未配置完成的菜单,onActionModeStarted里直接调用super方法即可。
方案2:主题配置覆盖系统默认样式(无反射)
不想用反射的话,可以直接在App主题里覆盖浮动ActionMode的弹出菜单样式,强制开启图标显示:
<!-- 应用主主题 --> <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"> <!-- 其他原有主题属性保持不变 --> <item name="actionModePopupWindowStyle">@style/FixIconActionModePopup</item> </style> <style name="FixIconActionModePopup" parent="Widget.MaterialComponents.PopupWindow.FloatingActionMode"> <item name="android:popupMenuStyle">@style/ForceShowIconMenu</item> </style> <style name="ForceShowIconMenu" parent="Widget.AppCompat.PopupMenu"> <item name="android:optionalIconsVisible">true</item> </style>
如果项目已经配置过自定义的ActionMode样式,只需要把android:optionalIconsVisible属性加进去即可。
注意事项
- 浮动ActionMode的菜单项图标建议使用24dp尺寸的资源,过大会被系统自动裁剪导致显示异常。
- 所有菜单配置逻辑要在调用
super.onActionModeStarted或者super.onCreateActionMode之前执行,否则系统会提前完成菜单渲染,配置不生效。
内容的提问来源于stack exchange,提问作者Kanika
相关产品推荐
相关产品推荐


