以编程方式更改MenuItem文本颜色

时间:2015-07-30 01:03:43

标签: android android-actionbar

所以我有一个菜单项,定义为:

<item
    android:id="@+id/action_live"
    android:title="@string/action_live"
    android:orderInCategory="1"
    app:showAsAction="ifRoom|withText" />

它显示为文本,如下所示:

Screenshot 1

我想以编程方式更改&#34; LIVE&#34;文字颜色。我已经搜索了一段时间,我发现了一种方法:

全局定义:

private Menu mOptionsMenu;

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    mOptionsMenu = menu;
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

我做:

MenuItem liveitem = mOptionsMenu.findItem(R.id.action_live);
SpannableString s = new SpannableString(liveitem.getTitle().toString());
s.setSpan(new ForegroundColorSpan(Color.RED), 0, s.length(), 0);
liveitem.setTitle(s);

但没有任何反应!

如果我对溢出菜单的项目执行相同操作,则可以:

Screenshot 2

app有一些限制:showAsAction =&#34; ifRoom | withText&#34;项目?有没有解决方法?

提前致谢。

9 个答案:

答案 0 :(得分:18)

这次参加派对的时间有点迟了,但我花了一些时间研究这个并找到了解决方案,这可能对其他试图做同样事情的人有用。有一些功劳归功于哈里什·斯里德哈兰(Harish Sridharan),指引我朝着正确的方向前进。

您可以使用findViewById(R.id.MY_MENU_ITEM_ID)找到菜单项(假设菜单已经创建并准备好),然后按照Harish的建议将其投射到TextView实例,然后可以将其设置为必需的。

public class MyAwesomeActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
    super.onCreate(savedInstanceState);

    // Force invalidatation of the menu to cause onPrepareOptionMenu to be called
    invalidateOptionsMenu();
}

private void styleMenuButton() {
    // Find the menu item you want to style
    View view = findViewById(R.id.YOUR_MENU_ITEM_ID_HERE);

    // Cast to a TextView instance if the menu item was found
    if (view != null && view instanceof TextView) {
        ((TextView) view).setTextColor( Color.BLUE ); // Make text colour blue
        ((TextView) view).setTextSize(TypedValue.COMPLEX_UNIT_SP, 24); // Increase font size
    }
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    boolean result = super.onPrepareOptionsMenu(menu);
    styleMenuButton();
    return result;
}

}

这里的技巧是强制菜单在活动的onCreate事件中失效(从而导致onPrepareMenuOptions比正常情况更快地被调用。在此方法中,我们可以根据需要找到菜单项和样式。

答案 1 :(得分:7)

@RRP给我一个线索,但他的解决方案对我不起作用。 @Box给了另一个,但他的回答看起来有点不那么清晰。谢谢他们。所以根据他们的说法,我有一个完整的解决方案。

private static void setMenuTextColor(final Context context, final Toolbar toolbar, final int menuResId, final int colorRes) {
    toolbar.post(new Runnable() {
        @Override
        public void run() {
            View settingsMenuItem =  toolbar.findViewById(menuResId);
            if (settingsMenuItem instanceof TextView) {
                if (DEBUG) {
                    Log.i(TAG, "setMenuTextColor textview");
                }
                TextView tv = (TextView) settingsMenuItem;
                tv.setTextColor(ContextCompat.getColor(context, colorRes));
            } else { // you can ignore this branch, because usually there is not the situation
                Menu menu = toolbar.getMenu();
                MenuItem item = menu.findItem(menuResId);
                SpannableString s = new SpannableString(item.getTitle());
                s.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, colorRes)), 0, s.length(), 0);
                item.setTitle(s);
            }

        }
    });
}

答案 2 :(得分:5)

它只在检查后变成文本视图,其真正的类是ActionMenuItemView,我们可以在其上进一步设置文本颜色,如下所示:

public static void setToolbarMenuItemTextColor(final Toolbar toolbar,
                                               final @ColorRes int color,
                                               @IdRes final int resId) {
    if (toolbar != null) {
        for (int i = 0; i < toolbar.getChildCount(); i++) {
            final View view = toolbar.getChildAt(i);
            if (view instanceof ActionMenuView) {
                final ActionMenuView actionMenuView = (ActionMenuView) view;
                // view children are accessible only after layout-ing
                actionMenuView.post(new Runnable() {
                    @Override
                    public void run() {
                        for (int j = 0; j < actionMenuView.getChildCount(); j++) {
                            final View innerView = actionMenuView.getChildAt(j);
                            if (innerView instanceof ActionMenuItemView) {
                                final ActionMenuItemView itemView = (ActionMenuItemView) innerView;
                                if (resId == itemView.getId()) {
                                    itemView.setTextColor(ContextCompat.getColor(toolbar.getContext(), color));
                                }
                            }
                        }
                    }
                });
            }
        }
    }
}

答案 3 :(得分:1)

您可以将颜色更改放入onPrepareOptionsMenu:

override fun onPrepareOptionsMenu(menu: Menu?): Boolean 
{

    val signInMenuItem = menu?.findItem(R.id.menu_main_sign_in)

    val title = signInMenuItem?.title.toString()

    val spannable = SpannableString(title)

    spannable.setSpan(
       ForegroundColorSpan(Color.GREEN),
       0,
       spannable.length,
       Spannable.SPAN_INCLUSIVE_INCLUSIVE)

    SgnInMenuItem?.title = spannable

    return super.onPrepareOptionsMenu(menu)

}

当然,您可以在上方将其缩短...

现在您可以更改其他(即viewmodel)值的颜色外观了。

RG

答案 4 :(得分:0)

文档定义的

MenuItem是一个接口。在将其描绘为菜单之前,它肯定会使用视图窗口小部件来实现。大多数情况下,这些菜单项都实现为TextView。您可以使用UiAutomatorViewer查看视图层次结构,甚至可以使用 [sdk-home] / tools /中的hierarchyviewer。为MenuItem添加了一个示例uiautomatorviewer屏幕截图

因此,您始终可以对您的MenuItem进行类型转换并设置颜色。

TextView liveitem = (TextView)mOptionsMenu.findItem(R.id.action_live);
liveitem.setTextColor(Color.RED);

编辑:

由于有人要求查看如何使用此工具,我还要添加更多内容。

确保您已将环境变量 $ ANDROID_HOME 设置为指向SDK主页。

在您的终端中:

cd $ANDROID_HOME
./tools/uiautomatorviewer

此工具将打开。

菜单中的第二个或第三个按钮(参见屏幕截图)将捕获连接的设备或模拟器的屏幕截图,您可以检查视图及其层次结构。单击视图将描述视图及其信息。它是专门用于测试的工具,您可以检查任何应用程序。

请参阅开发者网站以获取更多信息:uiautomatorviewer

uiautomatorviewer

答案 5 :(得分:0)

我花了很多时间来解决这个问题,终于使它投入工作。 Android 6和7有一个简单的解决方案,但在Android 5上却不起作用。此代码对所有这些都适用。因此,如果您在Kotlin进行此操作,这是我的建议:

override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.my_menu, menu)
        setToolbarActionTextColor(menu, R.color.black)
        this.menu = menu
        return true
}

private fun setToolbarActionTextColor(menu: Menu, color: Int) {
        val tb = findViewById<Toolbar>(R.id.toolbar)
        tb?.let { toolbar ->
            toolbar.post {
                val view = findViewById<View>(R.id.my_tag)
                if (view is TextView) {
                    view.setTextColor(ContextCompat.getColor(this, color))
                } else {
                    val mi = menu.findItem(R.id.my_tag)
                    mi?.let {
                        val newTitle: Spannable = SpannableString(it.title.toString())
                        val newColor = ContextCompat.getColor(this, color)
                        newTitle.setSpan(ForegroundColorSpan(newColor),
                                0, newTitle.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
                        it.title = newTitle
                    }
                }
            }
        }
}

答案 6 :(得分:0)

要更改菜单项的颜色,您可以找到该菜单项,从中提取标题,将其放入“可扩展字符串”中,并为其设置前景色。试试这段代码

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    MenuItem mColorFullMenuBtn = menu.findItem(R.id.action_submit); // extract the menu item here

    String title = mColorFullMenuBtn.getTitle().toString();
    if (title != null) {
        SpannableString s = new SpannableString(title);
        s.setSpan(new ForegroundColorSpan(Color.parseColor("#FFFFFF")), 0, s.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); // provide whatever color you want here.
        mColorFullMenuBtn.setTitle(s);
    }
   return super.onCreateOptionsMenu(menu);
}

答案 7 :(得分:0)

这很复杂,但是您可以使用app:actionLayout属性。例如,

my_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/englishList"
        android:orderInCategory="1"
        app:showAsAction="ifRoom|withText"
        app:actionLayout="@layout/custom_menu_item_english_list"
        android:title=""/>
</menu>

custom_menu_item_english_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical">
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/englishListWhiteText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFF"
        android:lineHeight="16dp"
        android:textSize="16sp"
        android:text="英文"
        android:layout_marginRight="8dp"/>
</LinearLayout>

MainActivity.java:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.my_menu, menu);
    MenuItem item = menu.findItem(R.id.englishList); 
    item.getActionView().findViewById(R.id.englishListWhiteText)
        .setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v){
                //Handle button click. 
            }
        });
    return true;
}

结果:

enter image description here

更多详细示例= https://medium.com/@info.anikdey003/custom-menu-item-using-action-layout-7a25118b9d5

答案 8 :(得分:0)

如果您使用弹出菜单功能来显示应用程序中的菜单项并尝试更改菜单列表中文本项的设计或颜色,请先在 style.xml 文件中创建一个样式项:

<style name="PopupMenuStyle" parent="Widget.AppCompat.PopupMenu">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_gravity">center</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textColor">@color/ColorPrimary</item>
    <item name="android:textSize">@dimen/textsize</item>
    <item name="android:fontFamily">@font/myfonts</item></style>

并在您的代码中使用此样式:

val popupWrapper = ContextThemeWrapper(this, R.style.PopupMenuStyle)
val popup = PopupMenu(popupWrapper, your_menu_view)