我知道使用本地API是不可能实现的。有没有其他方法来实现这种视图?
我知道使用本地API是不可能实现的。有没有其他方法来实现这种视图?
一般来说,之前发布的答案是可以的。但它基本上移除了溢出菜单的默认行为,比如在不同屏幕尺寸上可以显示多少个图标,以及当它们无法显示时如何将它们放入溢出菜单中。通过以上操作,您将删除许多重要的功能。
更好的方法是告诉溢出菜单直接显示图标。您可以通过向Activity添加以下代码来实现此目的。
@Override
public boolean onMenuOpened(int featureId, Menu menu)
{
if(featureId == Window.FEATURE_ACTION_BAR && menu != null){
if(menu.getClass().getSimpleName().equals("MenuBuilder")){
try{
Method m = menu.getClass().getDeclaredMethod(
"setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
}
catch(NoSuchMethodException e){
Log.e(TAG, "onMenuOpened", e);
}
catch(Exception e){
throw new RuntimeException(e);
}
}
}
return super.onMenuOpened(featureId, menu);
}
appcompat-v7:22.x
中不再调用onMenuOpened(FEATURE_ACTION_BAR)
,这可能是有意为之,也可能不是,请参见http://b.android.com/171440。将代码移至`onPrepareOptionsMenu`应该是可以的。 - TWiStErRob根据之前的答案,我尝试了这个方法,在较新版本的支持库(25.1)中可以正常工作:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
if(menu instanceof MenuBuilder){
MenuBuilder m = (MenuBuilder) menu;
//noinspection RestrictedApi
m.setOptionalIconsVisible(true);
}
return true;
}
MenuBuilder.setOptionalIconsVisible
,请使用Android Support 25.3.1。请注意不要改变原意,同时保证语言通俗易懂。 - Francesco Vadicamo@SuppressLint("RestrictedApi")
- tim4dev<item
android:id="@+id/empty"
android:icon="@drawable/ic_action_overflow"
android:orderInCategory="101"
android:showAsAction="always">
<menu>
<item
android:id="@+id/action_show_ir_list"
android:icon="@drawable/ic_menu_friendslist"
android:showAsAction="always|withText"
android:title="List"/>
</menu>
</item>
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_tab, menu);
MenuItem item = menu.findItem(R.id.action_login);
SpannableStringBuilder builder = new SpannableStringBuilder("* Login");
// replace "*" with icon
builder.setSpan(new ImageSpan(this, R.drawable.login_icon), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);
}
Simon的回答对我非常有用,因此我想分享一下我如何按照建议将它实现到onCreateOptionsMenu
方法中:
Simon的答案对我很有帮助,所以我想分享一下我如何像他建议的那样把它实现到onCreateOptionsMenu
方法中:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_action_bar, menu);
// To show icons in the actionbar's overflow menu:
// https://dev59.com/fWMl5IYBdhLWcg3we243
//if(featureId == Window.FEATURE_ACTION_BAR && menu != null){
if(menu.getClass().getSimpleName().equals("MenuBuilder")){
try{
Method m = menu.getClass().getDeclaredMethod(
"setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
}
catch(NoSuchMethodException e){
Log.e(TAG, "onMenuOpened", e);
}
catch(Exception e){
throw new RuntimeException(e);
}
}
//}
return super.onCreateOptionsMenu(menu);
}
public static void setOptionalIconsVisible(Menu menu) {
if (menu instanceof MenuBuilder) {
MenuBuilder menuBuilder = (MenuBuilder) menu;
menuBuilder.setOptionalIconsVisible(true);
}
}
}` - Makotosan在@Desmond Lua的上面的答案基础上,我创建了一个静态方法,用于在下拉列表中使用在XML中声明的可绘制对象,并确保其着色不影响常量可绘制对象状态。
/**
* Updates a menu item in the dropdown to show it's icon that was declared in XML.
*
* @param item
* the item to update
* @param color
* the color to tint with
*/
private static void updateMenuWithIcon(@NonNull final MenuItem item, final int color) {
SpannableStringBuilder builder = new SpannableStringBuilder()
.append("*") // the * will be replaced with the icon via ImageSpan
.append(" ") // This extra space acts as padding. Adjust as you wish
.append(item.getTitle());
// Retrieve the icon that was declared in XML and assigned during inflation
if (item.getIcon() != null && item.getIcon().getConstantState() != null) {
Drawable drawable = item.getIcon().getConstantState().newDrawable();
// Mutate this drawable so the tint only applies here
drawable.mutate().setTint(color);
// Needs bounds, or else it won't show up (doesn't know how big to be)
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
ImageSpan imageSpan = new ImageSpan(drawable);
builder.setSpan(imageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);
}
}
当在活动中使用时,它的使用看起来会像这样。根据您的个人需求,这可能会更加优雅。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_activity_provider_connect, menu);
int color = ContextCompat.getColor(this, R.color.accent_dark_grey);
updateMenuWithIcon(menu.findItem(R.id.email), color);
updateMenuWithIcon(menu.findItem(R.id.sms), color);
updateMenuWithIcon(menu.findItem(R.id.call), color);
return true;
}
public boolean onCreateOptionsMenu(Menu menu){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.toolbar_menu,menu);
if(menu instanceof MenuBuilder) { //To display icon on overflow menu
MenuBuilder m = (MenuBuilder) menu;
m.setOptionalIconsVisible(true);
}
return true;
} `
目前最佳但未被接受的解决方案可能适用于旧平台。无论如何,在新的AppCompat21+中,所需方法不存在,而方法getDeclaredMethod
会返回异常NoSuchMethodException
。
因此,我使用的解决方法(在4.x、5.x设备上测试过并可行)基于直接更改背景参数。只需将此代码放入您的Activity类中即可。
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
// enable visible icons in action bar
if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
try {
Field field = menu.getClass().
getDeclaredField("mOptionalIconsVisible");
field.setAccessible(true);
field.setBoolean(menu, true);
} catch (IllegalAccessException | NoSuchFieldException e) {
Logger.w(TAG, "onMenuOpened(" + featureId + ", " + menu + ")", e);
}
}
}
return super.onMenuOpened(featureId, menu);
}
-keepclassmembers **.MenuBuilder { void setOptionalIconsVisible(boolean); }
。 - TWiStErRob@Simon的答案真的很有效...但如果你正在使用AppCompat Activity...你需要使用以下代码...因为在appcompat-v7:22.x中onMenuOpened()不再被调用。
@Override
protected boolean onPrepareOptionsPanel(View view, Menu menu) {
if(menu != null){
if(menu.getClass().getSimpleName().equals("MenuBuilder")){
try{
Method m = menu.getClass().getDeclaredMethod(
"setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
}
catch(NoSuchMethodException e){
Log.e(Constants.DEBUG_LOG, "onMenuOpened", e);
}
catch(Exception e){
throw new RuntimeException(e);
}
}
}
return super.onPrepareOptionsPanel(view, menu);
}
Kotlin:
@SuppressLint("RestrictedApi")
fun Menu.showOptionalIcons() {
this as MenuBuilder
setOptionalIconsVisible(true)
}