更改由 xml 布局制作的工具栏菜单上的菜单项

Changing menu items on a toolbar menu made from a xml layout

所以我的应用程序中有这个工具栏,我想根据用户是否登录显示不同的菜单项。当用户登录或注销时,我想更新我的布局,现在是工具栏菜单来表示更改。但出于某种原因,我的菜单项根本没有被删除,无论登录状态如何,所有菜单项始终可见。

我的菜单项:

<menu
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_add"
        android:icon="@drawable/ic_action_add"
        android:title="@string/action_add"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@+id/action_login"
        android:icon="@drawable/ic_action_logged_out"
        android:title="@string/action_log_in"
        app:showAsAction="always"/>

    <item
        android:id="@+id/action_logout"
        android:icon="@drawable/ic_action_logged_in"
        android:title="@string/action_log_out"
        app:showAsAction="always"/>
</menu>

第一个菜单项应该只对已登录的用户可见。而且我想这是不言自明的,但我只希望其中一个日志 in/out 按钮根据登录可见状态。

我的Java代码:

protected void initializeToolbar(){
    myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    menu = myToolbar.getMenu();
    resetToolbarMenu();
    myToolbar.setOnMenuItemClickListener(this);
}

private void resetToolbarMenu(){
    menu.clear();
    getMenuInflater().inflate(R.menu.menu, menu);
    if(loginPrefs.getBoolean("login", false)) { //loginPrefs is reference to a SharedPreference object
        menu.removeItem(1);
    } else {
        menu.removeItem(2);
        menu.removeItem(0);
    }
}

我有两种方法的原因是我只想设置一次工具栏和侦听器,但我希望能够在用户每次登录时更改菜单 in/out 而无需重新加载页面。

成功登录后,将再次调用resetToolbarMenu()方法。

我想 menu.remove(0) 不会更新 UI,但如果不先膨胀菜单对象然后从工具栏中获取它,我找不到另一种方法来访问我的菜单对象,我假设inflation 决定哪些项目可见。基本上,我找不到一种方法在膨胀或以膨胀以外的其他方式更新 UI 之前删除任何菜单项。

解决方案:

我将 java 代码更改为如下内容:

protected void initializeToolbar(){
    myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(myToolbar);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);
    return super.onCreateOptionsMenu(menu); // Don't know if this is necessary or if returning true is prefered.
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    if(loginPrefs.getBoolean("login", false)) {
        menu.getItem(0).setVisible(true);
        menu.getItem(1).setVisible(false);
        menu.getItem(2).setVisible(true);
    } else {
        menu.getItem(0).setVisible(false);
        menu.getItem(1).setVisible(true);
        menu.getItem(2).setVisible(false);
    }
    return true;
}

我还必须在 logout/login 上调用 invalidateOptionsMenu() 来更新 toolbar/menu。但是,每当您打开工具栏本身未显示的项目的菜单时,也会自动调用 onPrepareOptionsMenu()。

PS: OnCreateOptionsMenuOnPrepareOptionsMenu 不会被使用,除非你记得 setSupportActionBar(myToolbar) 因为我忘了。

您必须覆盖 activity 中的 onPrepareOptionsMenu 才能更改菜单​​中的项目。

来自文档:

准备要显示的屏幕标准选项菜单。每次显示菜单时,都会在显示菜单之前调用它。您可以使用此方法高效地 enable/disable 项目或以其他方式动态修改内容。

您可以通过覆盖 onCreateOptionsMenu 创建选项菜单。您可以创建 2 xml 并根据您的逻辑对其中之一进行膨胀。要强制重绘菜单,您可以调用 invalidateOptionsMenu.

例如

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    if (login) {
         inflater.inflate(R.menu.login_menu, menu);
    } else {
         inflater.inflate(R.menu.logout_menu, menu);
    }
    return true;
}

并在外部更改标志并强制重绘

login = false; // or true
invalidateOptionsMenu();