我该如何动态创建菜单项?

64

我正在开发一个Android应用程序,尝试构建一个用户管理系统,用户可以登录、注销等。如果用户已注销,我想显示一个登录菜单项,如果用户已登录,则显示一个注销按钮。如何动态实现这个功能?

目前的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/add" android:title="Add" android:icon="@drawable/ic_menu_add"/>
  <item android:id="@+id/list" android:title="List" android:icon="@drawable/ic_menu_list"/>
  <item android:id="@+id/refresh" android:title="Refresh" android:icon="@drawable/ic_menu_refresh"/>
  <item android:id="@+id/login" android:title="Login" android:icon="@drawable/ic_menu_login"/>
</menu>

这是我现在的Java代码:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    new MenuInflater(this).inflate(R.menu.activity_main, menu);
    return(super.onCreateOptionsMenu(menu));
}

@Override
public boolean onOptionsItemSelected(MenuItem item) 
{
    System.out.println(item.getItemId()==R.id.add);
    if (item.getItemId()==R.id.add)
    {
        //Cannot add spot unless we have obtained the users current location. 
        if((currentLat != 0) && (currentLng != 0))
        {

            System.out.println("loggedin? : "  + auth.isLoggedIn());
            if(!auth.isLoggedIn())
            {
                Toast.makeText(MainActivity.this, "You must be logged in to add a new spot",
                        Toast.LENGTH_LONG).show();
            }
            else
            {


                Intent addIntent = new Intent(MainActivity.this, AddSpot.class);
                Bundle b = new Bundle();
                b.putDouble("currentLat", currentLat);
                b.putDouble("currentLng", currentLng);
                addIntent.putExtras(b);
                startActivity(addIntent);
                return(true);
            }
        }
    }   
    else if(item.getItemId()==R.id.list)
    {
        //Pointless showing them a blank screen if nothing is retrieved from the server
        if(list != null)
        {
            Intent listIntent = new Intent(MainActivity.this, ListLocations.class);
            listIntent.putExtra("list", list);
            startActivity(listIntent);
            return(true);
        }
    }

    if(item.getItemId()==R.id.refresh)
    {
        finish();
        startActivity(getIntent());
        return(true);       
    }

    if(item.getItemId()==R.id.login)
    {
        Intent loginIntent = new Intent(MainActivity.this, LoginActivity.class);
        startActivity(loginIntent);
        return(true);   
    }

    return(super.onOptionsItemSelected(item));
}
6个回答

111

如何在Android Activity中动态添加菜单项

public class yourActivity extends Activity {
    ...
    private static final int MENU_ADD = Menu.FIRST;
    private static final int MENU_LIST = MENU.FIRST + 1;
    private static final int MENU_REFRESH = MENU.FIRST + 2;
    private static final int MENU_LOGIN = MENU.FIRST + 3;

    /**
     * Use if your menu is static (i.e. unchanging)
     */
    /*
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0, MENU_ADD, Menu.NONE, R.string.your-add-text).setIcon(R.drawable.your-add-icon);
        menu.add(0, MENU_LIST, Menu.NONE, R.string.your-list-text).setIcon(R.drawable.your-list-icon);
        menu.add(0, MENU_REFRESH, Menu.NONE, R.string.your-refresh-text).setIcon(R.drawable.your-refresh-icon);
        menu.add(0, MENU_LOGIN, Menu.NONE, R.string.your-login-text).setIcon(R.drawable.your-login-icon);
        return true;
    }
    */

    /**
     * Gets called every time the user presses the menu button.
     * Use if your menu is dynamic.
     */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.clear();
        if(enableAdd)
            menu.add(0, MENU_ADD, Menu.NONE, R.string.your-add-text).setIcon(R.drawable.your-add-icon);
        if(enableList)
            menu.add(0, MENU_LIST, Menu.NONE, R.string.your-list-text).setIcon(R.drawable.your-list-icon);
        if(enableRefresh)
            menu.add(0, MENU_REFRESH, Menu.NONE, R.string.your-refresh-text).setIcon(R.drawable.your-refresh-icon);
        if(enableLogin)
            menu.add(0, MENU_LOGIN, Menu.NONE, R.string.your-login-text).setIcon(R.drawable.your-login-icon);
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);

        switch (item.getItemId()) {
        case MENU_ADD: doAddStuff(); break;
        case MENU_LIST: doListStuff(); break;
        case MENU_REFRESH: doRefreshStuff(); break;
        case MENU_LOGIN: doLoginStuff(); break;
        }
        return false;
    }
以下是一个具体的例子,如果用户已登录,则添加MENU_LOGOUT选项。
    private static final int MENU_LOGOUT = MENU.FIRST + 4;

    public boolean onPrepareOptionsMenu(Menu menu) {
        ...
        if(auth.isLoggedIn()) {
            menu.add(0, MENU_LOGOUT, Menu.NONE, R.string.your-logout-text).setIcon(R.drawable.your-logout-icon);
        }
        ...
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        ...
        case MENU_LOGOUT:
            if(auth.isLoggedIn()) {
                doLogout();
            } else {
                Toast.makeText(this, "You must have somehow been logged out between the time the menu button was pressed and now.", Toast.DURATION_LONG).show();
            }
            break;
        ...
    }

就是这样,没有别的了。


你好,谢谢。你能提供一个例子展示如果用户已经登录就显示注销吗?我应该在哪个方法中添加这个逻辑?而且,我不明白 MENU_ADD 等变量的含义。 - Johnathan Au
menuId值是必需的,这样您就可以在onOptionsItemSelected()中处理菜单活动时知道用户按下了哪个菜单项。 - David Manpearl
你必须为每个项目重新创建if()逻辑。在onPrepareOptionsMenu()中,必须放置决定菜单项是否应显示的逻辑。作为一种良好的实践,您还应该在onOptionsItemSelected()中重新创建相同的逻辑。这仅是为了防止在用户第一次按下菜单按钮和最终按下特定菜单项按钮之间的潜在长时间间隔期间发生更改(即他在选择项目之前将菜单显示了多长时间)。不要忘记为正确答案点赞(三角形)和接受(勾选)。 - David Manpearl
1
项目ID值(即MENU_LOGOUT)不必连续。它们可以是任何数字。您可以拥有任意数量。只是不要重复任何值。仅在需要时显示所需的值。因此,即使某些菜单标签很少显示,也可以为每个可能的菜单标签之一拥有其中之一。 - David Manpearl
我有一个疑问...假设我现在从后端获取了5个菜单选项(因为随时可能添加另一个菜单选项),那么应用程序是否会每次都从后端获取菜单来显示每个视图?有没有更好的方法? - Abhinav
显示剩余2条评论

8
在我的情况下,菜单项存储在ArrayList中 - 尝试使用这个方法,希望能帮到你 :)
public void onClick(View v)
{
    PopupMenu menu = new PopupMenu(DialogCheckBox.this, v);
    for (String s : limits) { // "limits" its an arraylist  
        menu.getMenu().add(s);
    }
    menu.show();
}

谢谢,这太棒了。正是我想要的。 - Prinkal Kumar
1
请问,如何在其项目上应用点击监听器? - Prinkal Kumar

7
你可以调用invalidateOptionsMenu()(注意:需要使用像actionBarSherlock这样的兼容库才能访问,以便支持低API版本),然后根据状态更新菜单项。
在那里,您可以隐藏登录操作项并显示注销操作项。
您还可以尝试更新图标本身,但我从未尝试过。

1
很好的额外细节。这是必需的,要像@johnathan-au提出的那样用LOGOUT图标替换LOGIN,因为它会导致onPrepareOptionsMenu()再次被调用。 - Someone Somewhere

1
private void getPopup(final TextView textView, ArrayList<String> arrayList) {
        final PopupMenu popupMenu = new PopupMenu(sContext, textView);
        for (int i = 0; i < arrayList.size(); i++) {
            popupMenu.getMenu().add(arrayList.get(i));
        }
        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                textView.setText(item.getTitle());
                return false;
            }
        });
        popupMenu.show();
    }

如果您的数据来自 Apis 并且您需要在弹出窗口中显示数据,则此代码可以帮助您。此外,它还可用于动态弹出窗口。 - Safal Bhatia

0

创建菜单项的简单方法:

Dynamic_PopUpMenu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PopupMenu menu = new PopupMenu(DialogCheckBox.this, v);
                menu.getMenu().add("AGIL"); // menus items 
                menu.getMenu().add("AGILANBU"); // menus items
                menu.getMenu().add("AGILarasan");
                menu.getMenu().add("Arasan");
                menu.show();
            }
        });

试试这个 :)


0

这真的很容易

创建菜单如下

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    for (int i = 0; i < list.size(); i++) {
        menu.add(0, i, 0, "Menu Name").setShortcut('5', 'c');
    }

    return true;
}

获取从点击菜单中的详细信息

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    int id = item.getItemId(); //to get the selected menu id
    String name = item.getTitle(); //to get the selected menu name

    return super.onOptionsItemSelected(item);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接