OptionMenu基本使用

下图是一个基本的OptionMenu,基本使用是三个步骤:创建资源文件、重写onCreateOptionsMenu加载菜单、重写onOptionsItemSelected处理点击事件。

Step1:创建资源文件

上图图中的三个点是其他隐藏的菜单,以下我们成为折叠菜单

这里简单说一下showAsAction,它包含但不仅有以下几种:

1、always

表示无论标题栏是否有地方,都显示在最上方,而不显示在折叠菜单中。

2、never

永远显示在折叠菜单中。

3、ifRoom

如果标题栏有地方就显示在标题栏,否则显示在折叠菜单中。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/btnAdd"
        android:icon="@mipmap/add"
        android:title="Add"
        app:showAsAction="always"></item>
    <item
        android:id="@+id/btnEdit"
        android:icon="@mipmap/edit"
        android:title="Edit"
        app:showAsAction="always"></item>
    <item android:title="OptionMenu1"></item>
    <item android:title="OptionMenu2"></item>
    <item android:title="OptionMenu3"></item>
</menu>

OptionMenu可同时在Activity和Fragment中加载,以下将演示两种方式。

在Activity中加载OptionMenu

Step2:重写onCreateOptionsMenu加载菜单

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

重写后要返回true,否则菜单不会显示,通过下图在Activity中的onCreateOptionsMenu注释就可以知道。

译为:为了显示这个menu,你必须返回true,如果你返回false这个menu将不会被显示出来。

Step3:重写onOptionsItemSelected处理点击事件

参数传来的就是我们点中的MenuItem对象,从中可以拿到Titile、Id等。如果这里不想将事件交给下一级处理直接返回true即可(这里主要是在Fragment也加载了OptionMenu的情况下,在下边展开来说)。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Toast.makeText(this,  item.getTitle(), Toast.LENGTH_SHORT).show();
    return true;
}

在Fragment中加载OptionMenu

以下是在Fragment中创建OptionMenu菜单,大致和Activity的差不多,不过有一点需要注意,就是我们必须设置setHasOptionsMenu(true)才会被显示出来。这样它就会被加载到它所处的Activity中了。如果Activity也有菜单那么会被合并在一起。如果我们Activity和Fragment同时都有,那么当点击某一个菜单项时会优先调用Activity中的onOptionsItemSelected,进而在调用Fragment中的,如果Activity中的onOptionsItemSelected返回了true则不会走到Fragment的onOptionsItemSelected(这里需要注意!)。

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_test1, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Toast.makeText(getContext(), item.getTitle(), Toast.LENGTH_SHORT).show();
    return true;
}
//注意下方代码!!!
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

动态操作Menu菜单

很多时候我们会根据实际需求在运行时动态的添加、移除、禁用、修改菜单,这些都是可以做到的,而且相对也比较简单,我们只需要保留在onCreateOptionsMenu的Menu对象即可,然后对这个对象进行操作就能实现这些功能。

private Menu mMenu;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_home, menu);
    this.mMenu = menu;
    return false;
}
int menuId = R.id.btnAdd;//菜单的ID
MenuItem menuItem = mMenu.findItem(menuId);//通过菜单ID找到菜单对象

//修改一个菜单项
menuItem.setTitle("New Title");
//禁用一个菜单项
menuItem.setEnabled(false);
//删除一个菜单项
mMenu.removeItem(menuId);
//隐藏一个菜单项
menuItem.setVisible(false);
//添加一个菜单项
mMenu.add("Add Menu");

其他:

如果你想要重新加载Menu可以调用Activity提供的invalidateOptionsMenu()函数。这里还需要说一个方法onPrepareOptionsMenu,它是在onCreateOptionsMenu之后的一个回调函数,通常在这里处理一些对菜单内容的修改。

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

以下是Activity类中的onPrepareOptionsMenu,这里我们主要来看它的注释。

译为:为屏幕的标准选项菜单的显示做准备。在菜单显示之前会被调用。你可以使用这个方法高效地开启/禁用菜单项,以及动态地修改其内容。

/**
 * Prepare the Screen's standard options menu to be displayed.  This is
 * called right before the menu is shown, every time it is shown.  You can
 * use this method to efficiently enable/disable items or otherwise
 * dynamically modify the contents.
 *
 * <p>The default implementation updates the system menu items based on the
 * activity's state.  Deriving classes should always call through to the
 * base class implementation.
 *
 * @param menu The options menu as last shown or first initialized by
 *             onCreateOptionsMenu().
 *
 * @return You must return true for the menu to be displayed;
 *         if you return false it will not be shown.
 *
 * @see #onCreateOptionsMenu
 */
public boolean onPrepareOptionsMenu(Menu menu) {
    if (mParent != null) {
        return mParent.onPrepareOptionsMenu(menu);
    }
    return true;
}

创建多级菜单

这个实现起来也很简单,直接操作我们在step1创建的xml资源文件就行了。首先根节点是menu,然后有item,然后item中又可以有menu,但是在menu节点中只能插入item和group节点而不能插入menu节点。不过个人不太推荐嵌套太多,易用性才差。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/btnAdd"
        android:icon="@mipmap/add"
        android:title="Add"></item>
    <item
        android:id="@+id/btnEdit"
        android:icon="@mipmap/edit"
        android:title="Edit"></item>
    <item android:title="OptionMenu1">
        <menu>
            <item android:title="SubItem1"></item>
            <item android:title="SubItem2"></item>
            <item android:title="SubItem3"></item>
        </menu>
    </item>
    <item android:title="OptionMenu2">
        <menu>
            <item android:title="SubItem1">
                <menu>
                    <item android:title="SubItem1"></item>
                    <item android:title="SubItem2"></item>
                    <item android:title="SubItem3"></item>
                </menu>
            </item>
            <item android:title="SubItem2"></item>
            <item android:title="SubItem3"></item>
        </menu>
    </item>
    <item android:title="OptionMenu3">
        <menu>
            <item android:title="SubItem1"></item>
            <item android:title="SubItem2"></item>
            <item android:title="SubItem3"></item>
        </menu>
    </item>
</menu>

继承父类的菜单

如果若干个Activity中存在相同的菜单和行为那么我们就可以抽出一个父类来专门处理这些行为。

Step1:创建资源文件

第一个名为menu_test1

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:title="M1-Test1"></item>
    <item android:title="M1-Test2"></item>
    <item android:title="M1-Test3"></item>
</menu>

第二个名为menu_test2

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:title="M2-Test1"></item>
    <item android:title="M2-Test2"></item>
    <item android:title="M2-Test3"></item>
</menu>

Step2:创建父Activity

我们让其创建了menu_test1菜单。

public class BaseActivity extends AppCompatActivity {
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_test1, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Toast.makeText(this, "BaseActivity:" + item.getTitle(), Toast.LENGTH_SHORT).show();
        return super.onOptionsItemSelected(item);
    }
}

Step3:继承父Activity

这里我们继承自上边创建的BaseActivity,我们在onCreateOptionsMenu中需要调用父类的onCreateOptionsMenu函数,然后再加载自己的。在onOptionsItemSelected函数我们调用了父类的onOptionsItemSelected函数用于让父类处理它的事件,当然我们也可以直接返回true,那么就不会调用父类的onOptionsItemSelected函数了,也就是把事件拦截了。当点击菜单中的某一项时会依次从当前所在的Activity向上进行回调。

public class MainActivity extends BaseActivity { 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_test2, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Toast.makeText(this, "MainActivity:" + item.getTitle(), Toast.LENGTH_SHORT).show();
        return super.onOptionsItemSelected(item);
        //return true;
    }

}

最终效果


qylost
3 声望2 粉丝

水之积也不厚,则其负大舟也无力;风之积也不厚,则其负大翼也无力。