Android学习第2篇——APP三种菜单详解

一、Android的Menu简介
Android系统的Menu主要有三种,OptionsMenu、ContextMenu、PopupMenu。以及菜单下面二级菜单SubMenu。

二、菜单的创建和使用

1、ContextMenu的创建和使用

ContextMenu针对在Activity的View中的所有控件,在长按View控件达到2秒钟弹出一个菜单项。

效果图:


实现方式:

①在Activity的OnCreate()方法中对Button按钮或者整个活动页面添加菜单响应监听:

//长按弹出上下文菜单的Button
Button contextMenu = (Button) findViewById(R.id.contextMenu);
//长按页面弹出上下文菜单
View view = findViewById(R.id.theLayout);
contextMenu.setOnCreateContextMenuListener(this);//为Button单独实现ContextMenu
this.registerForContextMenu(view);//长按页面空白地方会弹出Menu

因为Activity已经实现了OnCreateContextMenuListener,所以要在Activity中重写该类的一些方法:

②创建菜单

    //方法2,因为activity已经实现了OnCreateContextMenuListener,所以只需要重写onCreateContextMenu()方法
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {//这里是ContextMenu参数
        setContextMenuIconEnable(menu, true);//设置菜单的Icon图标可见,这个方法后面详解,针对Android高版本的菜单图标显示的方法
        menu.add(1, 2, 1, "添加").setIcon(android.R.drawable.ic_menu_add);
        menu.add(1, 3, 2, "删除").setIcon(android.R.drawable.ic_menu_delete);
        SubMenu m = menu.addSubMenu(0, 4, 3, "子菜单").setIcon(android.R.drawable.ic_media_next);
        m.add(0, 41, 0, "子菜单项1");
        m.add(0, 42, 0, "子菜单项2");
        m.add(0, 43, 0, "子菜单项3");
        super.onCreateContextMenu(menu, v, menuInfo);
    }

③菜单关闭

    @Override
    public void onContextMenuClosed(Menu menu) {
        Toast.makeText(this,"关闭",Toast.LENGTH_SHORT).show();
        super.onContextMenuClosed(menu);
    }

④菜单被点击

 @Override
    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case 2:
                Toast.makeText(this, "添加", Toast.LENGTH_SHORT).show();
                break;
            case 3:
                Toast.makeText(this, "删除", Toast.LENGTH_LONG).show();
                break;
            default:
                break;
        }
        return super.onContextItemSelected(item);
    }

ContextMenu菜单实现很简单

2、OptionsMenu的创建和使用

OptionsMenu在页面的标题栏的右侧创建一个菜单按钮,前提是菜单栏可以显示的时候才有,否则会被隐藏。点击按钮弹出OptionsMenu菜单。

效果图:



实现方式:

因为Activity活动本身支持OptionsMenu菜单,所以,我们只需要在Activity里面实现其方法即可

①创建菜单的方法

     * 当标题栏存在时,实现该方法则在标题栏出现Menu按钮,不实现则没有这个按钮
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {//这里是Menu
        //下面这个方法针对OptionsMenu和PopupMenu的图标显示设置,稍后讲解
        setOptionsAndPopupMenuIconEnable(menu, true);
        menu.add(0, 5, 1, "添加1").setIcon(android.R.drawable.ic_menu_add);
        //add()方法返回的是MenuItem对象,调用其setIcon()方法,为相应MenuItem设置Icon
        menu.add(0, 6, 2, "删除1").setIcon(android.R.drawable.ic_menu_delete);
        return super.onCreateOptionsMenu(menu);
    }

②点击菜单按钮时候触发方法

    //在点击OptionsMenu菜单按钮的时候触发,onPrepareOptionsPanel()这个方法先于onPrepareOptionsMenu()执行
    @Override
    protected boolean onPrepareOptionsPanel(View view, Menu menu) {
        Toast.makeText(this, "onPrepareOptionsPanel...", Toast.LENGTH_SHORT).show();
        return super.onPrepareOptionsPanel(view, menu);
    }
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        /**
         * 在onCreateOptionsMenu执行后,菜单被显示前调用;如果菜单已经被创建,则在菜单显示前被调用。 同样的,
         * 返回true则显示该menu,false 则不显示; (可以通过此方法动态的改变菜单的状态,比如加载不同的菜单等) TODO
         * Auto-generated method stub
         */
        Toast.makeText(this, "menu没出来时,处理方法自己定义即可", Toast.LENGTH_SHORT).show();
        return super.onPrepareOptionsMenu(menu);
    }

③当菜单的菜单项被点击的时候的响应函数

    //当OptionItem被选择的时候
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case 5:
                Toast.makeText(this, "添加1", Toast.LENGTH_SHORT).show();
                break;
            case 6:
                Toast.makeText(this, "删除1", Toast.LENGTH_LONG).show();
                break;
            case R.id.add_item:
                Toast.makeText(this, "add", Toast.LENGTH_LONG).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this, "remove", Toast.LENGTH_LONG).show();
                break;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }
④当菜单被关闭的时候(还存在问题)
    //没有测试出结果,以为是菜单关闭时候,以下三种结果不是
    //每次菜单被关闭时调用. (菜单被关闭有三种情形,menu按钮被再次点击、back按钮被点击或者用户选择了某一个菜单项)
    @Override
    public void onOptionsMenuClosed(Menu menu) {
        Toast.makeText(this, "关闭222222", Toast.LENGTH_SHORT).show();
        super.onOptionsMenuClosed(menu);
    }

3、PopupMenu菜单的创建和使用

PopupMenu菜单是通过点击View组件的时候触发Activity相应函数,从而新建PopupMenu菜单

效果图:

实现方式:

①为控件添加属性如下:

android:onClick="popUpMenu"

②在Activity中添加对应函数

    public void popUpMenu(View view) {
        /**
         * 第一个参数上下文对象
         * 第二个参数为锚点,何谓锚点?就是你这个弹出式菜单以哪个view为标准弹出,
         * 如果在这个view的下面有空间就在这个view下面的空间弹出,如果没有空间就
         * 在此view的上面弹出
         */
        PopupMenu popupMenu = new PopupMenu(this, view);
        setOptionsAndPopupMenuIconEnable(popupMenu.getMenu(), true);//显示Menu的图标方法,稍后详解
        /**
         * 第一个参数为菜单布局文件
         * 第二个参数为Menu对象,通过getMenu()获得。
         */
        getMenuInflater().inflate(R.menu.menu, popupMenu.getMenu());
        /**
         * 要想显示必须调用.show()方法
         */
        //弹出菜单的点击事件也没有回调事件,需要自己设置监听事件onMenuItemCilckListener(),
        //并在其中实现逻辑,代码如下:
        //值得注意的是最后的返回值,这个涉及到view的事件分发。简单的意思就是,返回true代码消耗这次点击事件,
        //事件不会继续传播,如果返回false则事件会继续传播的。
        //比如这个弹出菜单的又设置了setOnDismissListener这个事件,
        //那么如果返回true,则这个事件不起作用,返回false则点击事件处理完后,这个事件还会起作用。
        //但是亲测true好像没有用
        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                Toast.makeText(MainActivity.this, menuItem.getTitle().toString(), Toast.LENGTH_SHORT).show();
                return false;
            }
        });
        popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
            @Override
            public void onDismiss(PopupMenu popupMenu) {
                Toast.makeText(MainActivity.this, "PopupMenu的Dismiss", Toast.LENGTH_SHORT).show();
            }
        });
        popupMenu.setGravity(Gravity.BOTTOM);//没有用
        popupMenu.show();
    }

上面可以看出关于PopupMenu菜单的所有的实现以及点击按钮事件都在这个方法内完成。

三、关于菜单的创建说明

1、add方法的参数解析

//        add()方法的四个参数,依次是:
//        1、组别,如果不分组的话就写Menu.NONE,
//        2、Id,这个很重要,Android根据这个Id来确定不同的菜单
//        3、顺序,哪个菜单项在前面由这个参数的大小决定
//        4、文本,菜单项的显示文本
        menu.add(0, 5, 1, "添加1").setIcon(android.R.drawable.ic_menu_add);

2、通过布局文件创建菜单

①新建布局文件,在res资源目录下新建一个menu资源文件夹,选择类型就是menu。然后在menu文件下面新建一个menu.xml文件,这个名字可以自己取。下面包含了二级菜单的创建。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:icon="@android:drawable/ic_menu_add"
        android:title="Add" />
    <item
        android:id="@+id/remove_item"
        android:icon="@android:drawable/ic_popup_reminder"
        android:title="Remove" />
    <item
        android:id="@+id/item_china"
        android:orderInCategory="100"
        android:title="中国">
        <menu>
            <item
                android:id="@+id/item_beijing"
                android:orderInCategory="200"
                android:title="北京"/>
            <item
                android:id="@+id/item_shanghai"
                android:orderInCategory="200"
                android:title="上海"/>
        </menu>
    </item>
</menu>

②通过资源文件新建菜单

getMenuInflater().inflate(R.menu.menu, Menu);

通过该方法直接将meun.xml的菜单解析到Menu实例中。

四、关于菜单图片的显示问题

Android的4.0之前,设置图标是默认显示的,但是4.0之后,就不在默认了。现在针对三种菜单Menu的图标显示方法如下

1、针对ContextMenu菜单

    // 经过试验ContextMenu有效,对OptionMenu无效
    private void setContextMenuIconEnable(Menu menu, boolean enable) {
        if (menu != null) {
            //com.android.internal.view.menu.ContextMenuBuilder,这是菜单menu的实体类
            Log.d("AAA", menu.getClass().getName().toString());
            try {
                //这是ContextMenu加载菜单的Builder,com.android.internal.view.menu.MenuBuilder
                Class<?> clazz = Class.forName("com.android.internal.view.menu.MenuBuilder");
                Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                Log.d("aaa", m.toString());
                m.setAccessible(true);
                //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)
                m.invoke(menu, enable);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

2、针对PopupMenu和OptionsMenu菜单

   //这是针对OptionsMenu和PopupMenu菜单的设置Icon图标可见的方法
    private void setOptionsAndPopupMenuIconEnable(Menu menu, boolean enable) {
        if (menu != null) {
            Log.d("BBB", menu.getClass().getName().toString());
            if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
                try {
                    //这是OptionMenu加载菜单的Builder,android.support.v7.view.menu.MenuBuilder
                    //Class clazz = Class.forName("android.support.v7.view.menu.MenuBuilder");
                    Method m = menu.getClass().getDeclaredMethod(
                            "setOptionalIconsVisible", Boolean.TYPE);
                    m.setAccessible(true);
                    m.invoke(menu, enable);
                } catch (Exception e) {
                }
            }
        }
    }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值