一、 OptionMenu

1、首先在项目目录下的res资源目录下,新建一个资源文件夹menu

(1)res目录的位置如下

android menu 距离 android menu菜单_xml


(2)新建名称为menu的包

android menu 距离 android menu菜单_android studio_02

2、然后在menu的包下新建Menu Resource File资源文件

android menu 距离 android menu菜单_android menu 距离_03


(1)文件名字自己任意填写即可,我这里写的是optionmenu

android menu 距离 android menu菜单_xml_04


(2)然后点击ok即可,资源文件新建完成之后会出现以下xml界面

android menu 距离 android menu菜单_java_05


(3)此时的界面是最初的界面,然后我们开始书写菜单的界面,这里就简单的写一下菜单的选项,仅做测试学习,修改optionmenu.xml文件如下所示:

<?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:title="保存"
        android:id="@+id/save"
        app:showAsAction="always"/>
    <item android:title="设置"
        android:id="@+id/setting"/>
    <item
        android:title="更多" >
        <menu >
            <item android:title="退出"
                android:id="@+id/back"/>
            <item android:title="子菜单2" />
        </menu>
    </item>

</menu>

里面的属性我就不一一介绍了,都是一些比较基础的属性,不懂的可以自行查阅
3、将menu资源文件引入到你想要引入的Activity中,在这里我就默认引入到MainActivity中了
(1)首先将布局文件引入到MainActivity中,需要重写如下函数onCreateOptionsMenu,相信大家从英文单词也能看出来这是创建OptionMenu的意思,这里需要做的操作是利用getMenuInflater().inflate()函数将相关的menu资源引入到当前的view中,最后记得要返回true,代表我们已经完成对menu资源的引入

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //将菜单资源加载到当前的菜单资源
        getMenuInflater().inflate(R.menu.optionmenu,menu);
        return true;
    }

其实这是我们运行程序的话,我们已经能够看到菜单效果了,如下图:

android menu 距离 android menu菜单_java_06


android menu 距离 android menu菜单_android_07


但是此时并没有设置点击事件,所以我们点击菜单选项的话也不会发生响应,接下来我们就开始设置菜单选项的响应,由于是测试,这里简单使用Toast来进行测试,实际开发中只需要把Toast替换成响应的操作即可

(2)给菜单选项设置点击事件,这里我们只需要重写响应的方法即可

//菜单的点击事件
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
          case R.id.save:
            Toast.makeText(this, "保存", Toast.LENGTH_SHORT).show();
            break;
            case R.id.setting:
                Toast.makeText(this, "设置", Toast.LENGTH_SHORT).show();
                break;
            case R.id.back:
                Toast.makeText(this, "退出", Toast.LENGTH_SHORT).show();
                finish();
                break;
            default:super.onOptionsItemSelected(item);
        }
        return true;
    }

这里使用item.getItemId()方法来获取当前的选项实例,然后进行相应的响应操作,最后返回true即可,这样点击事件就已经设置完成了,点击保存选项时,会出现如下效果:

android menu 距离 android menu菜单_java_08


其他的菜单选项的效果是一样的,这里就不展示了,到此OptionMenu的基础知识就已经讲解完毕了,下面是另外两种的菜单了,一种叫上下文菜单(ContextMenu),一种叫弹出式菜单(PopupMenu)。在开始讲解这两个菜单之前,我需要在activity_main.xml布局文件中书写两个按钮,来测试上下文菜单和弹出式菜单,如下图:

android menu 距离 android menu菜单_java_09


代码如下:(很基本的布局,这里不做解释)

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/ctx_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="上下文菜单"/>


    <Button
        android:id="@+id/popup_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="弹出式菜单"/>

</LinearLayout>

二、ContextMenu

1、同上,先创建menu的资源文件
我这里就取名为context了,你们自行取名即可,建立资源文件的过程如上,这里就不详细讲了,建立好文件之后,将文件内容修改为如下(可自行修改,这里仅仅是作为案例讲解):

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:title="删除" android:id="@+id/delete"/>
    <item android:title="重命名" android:id="@+id/rename">
        <menu>
            <item android:title="返回"/>
            <item android:title="退出" android:id="@+id/back"/>
        </menu>
    </item>
</menu>

2、在MainActivity中去加载menu资源文件以及创建点击事件
(1)首先加载menu资源文件,这里会和OptionMenu的操作不太相同,这里需要创建一个内部类,如下图:

ActionMode.Callback cb = new ActionMode.Callback() {
        //处理绑定菜单
        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            getMenuInflater().inflate(R.menu.context,menu);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
            return false;
        }

        //处理点击事件
        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
            switch (menuItem.getItemId()){
            case R.id.delete:
                Toast.makeText(MainActivity.this, "delete", Toast.LENGTH_SHORT).show();
                break;
                case R.id.back:
                Toast.makeText(MainActivity.this, "back", Toast.LENGTH_SHORT).show();
                    break;
            case R.id.rename:
                Toast.makeText(MainActivity.this, "rename", Toast.LENGTH_SHORT).show();
                break;
                }
            return true;
        }

当我们在new ActionMode.Callback()对象的时候,回车,下面对应的函数就会自动生成了,并不需要我们自己书写,这里面我们主要关注的就是onCreateActionMode和onActionItemClicked这两个重载的方法,其实从他们的名字来看,相信你也能看出来它们分别是创建菜单和处理菜单的点击事件,上图中的代码,我简单处理了一下,做了几个简单的点击事件的响应,其实我们会发现,这里的加载资源文件以及处理选项的点击事件基本和OptionMenu是一样的,只不过是在不同的方法下执行的,基本的执行逻辑是一致的,或者可以说就是一样的。
3、在view的长按事件中启动上下文操作菜单模式
在这里需要说明的一点是,ContextMenu是需要长按来触发的,所以在这里绑定长按点击事件即可,代码如下:

findViewById(R.id.ctx_btn).setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        startActionMode(cb);
                        return false;
                    }
                });

和我们平时使用的按钮的点击事件基本是一样的,只不过函数名多了个Long,应该是很好理解的,也是需要我们长按才能触发,接下来我们长按上下文菜单按钮,会出现如下图的效果:

android menu 距离 android menu菜单_android studio_10


可见最上部出现了我们定义的删除和重命名两个选项,同时还有一个返回的箭头,点击返回的箭头就代表取消操作,这个返回按钮是ContextMenu自动为我们生成的,我们只需知道它的作用就行了,无需过多了解,另外的就是我们自己定义的选项按钮了,因为我们已经设置了点击事件,所以当我点击删除时,会出现以下效果:

android menu 距离 android menu菜单_android studio_11


即会Toast当前的操作,这就是ContextMenu的基本内容了,我们会发现实现的逻辑和前面的OptionMenu差不多,对你们来说应该不难。

三、弹出式菜单

1、同上新建menu资源文件
这里我为了节约时间,就不新建资源文件了,直接使用ContextMenu的资源文件了,因为其实menu资源文件是可以在任意的menu中引入的,当然这个要看具体的需求,那我这里为了测试,就不在新建新的menu资源文件了,大家可以自行选择新建和使用原来的文件,这个不会影响到功能的实现。
2、加载资源文件以及处理点击事件
这个菜单的加载menu资源文件和建立点击事件比较集中在一起,所以我就一并说了,这个菜单和前两个有点区别,他是直接在按钮的点击事件中处理的
代码如下图:

//首先获取到PopupMenu按钮的实例,然后进行处理点击事件
        Button popup = findViewById(R.id.popup_btn);
        popup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //实例化一个PopupMenu对象,传两个参数(Context,当前按钮的实例)
                PopupMenu menu = new PopupMenu(MainActivity.this,popup);
                //加载菜单资源
                menu.getMenuInflater().inflate(R.menu.context, menu.getMenu());
                //设置点击事件的响应
                menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem menuItem) {

                        switch (menuItem.getItemId()){
                            case R.id.delete:
                                Toast.makeText(MainActivity.this, "delete", Toast.LENGTH_SHORT).show();
                                break;
                            case R.id.back:
                                Toast.makeText(MainActivity.this, "back", Toast.LENGTH_SHORT).show();
                                break;
                            case R.id.rename:
                                Toast.makeText(MainActivity.this, "rename", Toast.LENGTH_SHORT).show();
                                break;
                        }
                        return true;
                    }
                });
                //一定要调用show()来显示弹出式菜单
                menu.show();
            }
        });

相关的描述以及处理的步骤我已经写在代码的注释里面了,相信大家都能够看得明白,其实,这三种菜单的原理以及处理的逻辑都是基本相同的,只不过是实现方式不同而已,你只要掌握好第一个OptionMenu的话,相信下面的两个菜单也是很容易掌握的。

四、给出完整代码

1、MainActivity

package com.example.menudemo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.PopupMenu;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //一、ContextMenu菜单:上下文菜单
            //1.ContextMenu的注册
        registerForContextMenu(findViewById(R.id.ctx_btn));
            //2.创建
                //就是重写onCreateContextMenu方法
            //3.菜单项的操作:点击事件的处理
                //重写onCreateOptionsMenu即可
            //4.为按钮设置上下文操作模式(创建了这个模式的话,前面的几步都可以省略)
                //实现ActionMode CallBack
                    //新建如下内部类
                //在view的长按事件中启动上下文操作模式
                findViewById(R.id.ctx_btn).setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        startActionMode(cb);
                        return false;
                    }
                });
        //二、弹出式菜单
        //首先获取到PopupMenu按钮的实例,然后进行处理点击事件
        Button popup = findViewById(R.id.popup_btn);
        popup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //实例化一个PopupMenu对象,传两个参数(Context,当前按钮的实例)
                PopupMenu menu = new PopupMenu(MainActivity.this,popup);
                //加载菜单资源
                menu.getMenuInflater().inflate(R.menu.context, menu.getMenu());
                //设置点击事件的响应
                menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem menuItem) {

                        switch (menuItem.getItemId()){
                            case R.id.delete:
                                Toast.makeText(MainActivity.this, "delete", Toast.LENGTH_SHORT).show();
                                break;
                            case R.id.back:
                                Toast.makeText(MainActivity.this, "back", Toast.LENGTH_SHORT).show();
                                break;
                            case R.id.rename:
                                Toast.makeText(MainActivity.this, "rename", Toast.LENGTH_SHORT).show();
                                break;
                        }
                        return true;
                    }
                });
                //一定要调用show()来显示弹出式菜单
                menu.show();
            }
        });
    }

    ActionMode.Callback cb = new ActionMode.Callback() {
        //处理绑定菜单
        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            getMenuInflater().inflate(R.menu.context,menu);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
            return false;
        }

        //处理点击事件
        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
            switch (menuItem.getItemId()){
            case R.id.delete:
                Toast.makeText(MainActivity.this, "delete", Toast.LENGTH_SHORT).show();
                break;
                case R.id.back:
                Toast.makeText(MainActivity.this, "back", Toast.LENGTH_SHORT).show();
                    break;
            case R.id.rename:
                Toast.makeText(MainActivity.this, "rename", Toast.LENGTH_SHORT).show();
                break;
                }
            return true;
        }

        //在操作结束时被调用
        @Override
        public void onDestroyActionMode(ActionMode actionMode) {
            Log.e("TAG", "结束!" );
        }
    };

//    @Override
//    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
//        getMenuInflater().inflate(R.menu.context,menu);
//        super.onCreateContextMenu(menu, v, menuInfo);
//    }
//
//    @Override
//    public boolean onContextItemSelected(@NonNull MenuItem item) {
//        switch (item.getItemId()){
//            case R.id.delete:
//                Toast.makeText(this, "delete", Toast.LENGTH_SHORT).show();
//                break;
//                case R.id.back:
//                Toast.makeText(this, "back", Toast.LENGTH_SHORT).show();
//                    break;
//            case R.id.rename:
//                Toast.makeText(this, "rename", Toast.LENGTH_SHORT).show();
//                break;
//        }
//        return super.onContextItemSelected(item);
//    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //将菜单资源加载到当前的菜单资源
        getMenuInflater().inflate(R.menu.optionmenu,menu);
        return true;
    }

    //菜单的点击事件
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
          case R.id.save:
            Toast.makeText(this, "保存", Toast.LENGTH_SHORT).show();
            break;
            case R.id.setting:
                Toast.makeText(this, "设置", Toast.LENGTH_SHORT).show();
                break;
            case R.id.back:
                Toast.makeText(this, "退出", Toast.LENGTH_SHORT).show();
                finish();
                break;
            default:super.onOptionsItemSelected(item);
        }
        return true;
    }
}

2、activity_main.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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/ctx_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="上下文菜单"/>


    <Button
        android:id="@+id/popup_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="弹出式菜单"/>

</LinearLayout>

3、optionmenu.xml

<?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:title="保存"
        android:id="@+id/save"
        app:showAsAction="always"/>
    <item android:title="设置"
        android:id="@+id/setting"/>
    <item
        android:title="更多" >
        <menu >
            <item android:title="退出"
                android:id="@+id/back"/>
            <item android:title="子菜单2" />
        </menu>
    </item>
</menu>

4、context.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:title="删除" android:id="@+id/delete"/>
    <item android:title="重命名" android:id="@+id/rename">
        <menu>
            <item android:title="返回"/>
            <item android:title="退出" android:id="@+id/back"/>
        </menu>
    </item>
</menu>

以上只是我个人在学习中学习到了的内容,可能我的理解会有错误和偏差,还希望各位大佬能够不吝指出我的问题所在,后面我会再次完善我的知识体系,以后也会不断分享我个人对于Android知识的理解和体会,谢谢大家!

创作不易,希望留个赞再走吧。