android之menu详解

一、OptionMenu的使用

       1、代码生成menu(重写activity的onCreateOptionMenu()方法)

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

    int groupId = 1;
    MenuItem item1 = menu.add(groupId, Menu.FIRST + 1, 1, "将第二组item不可见");
    item1.setIcon(R.mipmap.ic_launcher);
    menu.add(groupId, Menu.FIRST + 2, 2, "将第二组item可见");
    menu.add(groupId, Menu.FIRST + 3, 3, "将第二组item不可用");
    MenuItem item4 = menu.add(groupId, Menu.FIRST + 4, 4, "将第二组item可用");
    item4.setIcon(R.mipmap.ic_launcher);
    menu.add(groupId, Menu.FIRST + 5, 5, "将第二组item可单选");
    menu.add(groupId, Menu.FIRST + 6, 6, "将第二组item可多选");

    groupId = 2;
    MenuItem item7 = menu.add(groupId, Menu.FIRST + 7, 7, "menu2_1");
    item7.setIcon(R.mipmap.ic_launcher);
    MenuItem item8 = menu.add(groupId, Menu.FIRST + 8, 8, "menu2_2");
    item8.setIcon(R.mipmap.ic_launcher);

    SubMenu subMenu = menu.addSubMenu(groupId, Menu.FIRST + 9, 9, "sub menu");
    subMenu.add(groupId, Menu.FIRST + 10, 1, "sub1");
    subMenu.add(groupId, Menu.FIRST + 11, 2, "sub2");

    /**
     * 这个监听事件可以对item的点击事件进行拦截,拦截后的item在onOptionsItemSelected()中不会得到执行
     */
    item1.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            return true;//返回true为拦截,false不拦截
        }
    });

    return true;
}
使用menu.add(int groupId, int itemId, int order, charsequence title);


groupId:    可以对MenuItem进行分组,以便可以再代码中对某一组MenuItem进行操作,如menu.setGroupXXX();

itemId:    MenuItem的id,可以使用menuItem.getItemId(int id)获取到,便于对MenuItem的点击事件处理

order:     根据这个对menuItem的排序,越小排在越前面,如果某两个item的order相同,则按照代码添加顺序排列

title:         该menuitem的内容

/

menu.addSubMenu(int groupId, int itemId, int order, charsequence title);//使用同上


menuitem.setOnMenuItemClickListener()//可以直接在这里设置menuitem的点击事件,可以对onOptionsItemSeleted()进行拦截


onCreateOptionMenu()return true表示展示菜单,return false表示隐藏菜单


    2、添加menuitem的点击事件,在activity的onOptionsItemSeleted(MenuItem menuitem)中进行设置

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
        case Menu.FIRST + 1:
            menu.setGroupVisible(2, false);
            break;
        case Menu.FIRST + 2:
            menu.setGroupVisible(2, true);
            break;
        case Menu.FIRST + 3:
            menu.setGroupEnabled(2, false);
            break;
        case Menu.FIRST + 4:
            menu.setGroupEnabled(2, true);
            break;
        case Menu.FIRST + 5:
            menu.setGroupCheckable(2, true, true);
            break;
        case Menu.FIRST + 6:
            menu.setGroupCheckable(2, true, false);
            break;
        case Menu.FIRST + 7:
            Toast.makeText(this, "menu2_1", Toast.LENGTH_SHORT).show();
            break;
        case Menu.FIRST + 8:
            Toast.makeText(this, "menu2_2", Toast.LENGTH_SHORT).show();
            break;
        case Menu.FIRST + 10:
            Toast.makeText(this, "sub1", Toast.LENGTH_SHORT).show();
            break;
        case Menu.FIRST + 11:
            Toast.makeText(this, "sub2", Toast.LENGTH_SHORT).show();
            break;

    }



  3、xml生成menu

在res目录下新建menu目录,在这下面创建menu资源文件如mani_menu.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">
    <group android:id="@+id/group1" android:checkableBehavior="all">
        <item android:id="@+id/group1_item1" android:icon="@mipmap/ic_launcher" android:title="item1" app:showAsAction="always"></item>
        <item android:id="@+id/group1_item2" android:icon="@mipmap/ic_launcher" android:title="item2" app:showAsAction="always"></item>
        <item android:id="@+id/group1_item3" android:icon="@mipmap/ic_launcher" android:title="item3" app:showAsAction="always"></item>
        <item android:id="@+id/group1_item4" android:icon="@mipmap/ic_launcher" android:title="item4" app:showAsAction="always"></item>
        <item android:id="@+id/group1_item5" android:icon="@mipmap/ic_launcher" android:title="item5" app:showAsAction="always"></item>
        <item android:id="@+id/group1_item6"  android:title="点我" app:showAsAction="always">
            <menu>
                <item android:id="@+id/sub_item1" android:icon="@mipmap/ic_launcher" android:title="sub item1"></item>
                <item android:id="@+id/sub_item2" android:icon="@mipmap/ic_launcher" android:title="sub item2"></item>
                <item android:id="@+id/sub_item3" android:icon="@mipmap/ic_launcher" android:title="sub item3"></item>
            </menu>
        </item>
        <item android:id="@+id/group1_item7" android:icon="@mipmap/ic_launcher" android:title="item7" ></item>
    </group>
</menu>

注意xml中showAsAction的用法,根据编译版本的不同,使用不同,23使用的app:showAsAction  ,该属性可以设置menuitem是展示在actionbar上还是现实在overflow中

其中设置在actionbar上的menuitem只要设置了icon都会显示,但是在overflow中的menuitem的icon就分系统版本不同,而有不同,android 4.0之前会显示icon,android4.0之后显示不出icon,解决方法如下:

/**
 * 利用反射机制调用MenuBuilder中的setOptionIconsVisable(),
 * 如果是集成自AppCompatActivity则不行,需要在onPreareOptionPanel()中调用该方法
 * @param menu   该menu实质为MenuBuilder,该类实现了Menu接口
 * @param enable enable为true时,菜单添加图标有效,enable为false时无效。因为4.0系统之后默认无效
 */
private void setIconEnable(Menu menu, boolean enable) {
    if (menu != null) {
        try {
            Class clazz = menu.getClass();
            if (clazz.getSimpleName().equals("MenuBuilder")) {
                Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);

                //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)
                m.invoke(menu, enable);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
activity中传进来的menu其实是一个MenuBuilder的实例,而在MenuBuilder中有一个方法setOptionIconVisable(),这里只是用的向上转型,所以这里的menu调用不到,

而该方法又是一个访问修饰符为默认缺省的,所以只能利用反射机制

那么该在哪里调用该方法呢,这里为了兼容AppCompatActivity,我们在onPrepareOptionPanel()中调用

/**
 *  android 4.0以后使用AppCompatActivity必须在该方法中调用setIconEnable(),
 *  隐藏的menuitem的icon才会显示
 *  android 4.0以后其他的activity可以再onPrepreOptionMenu()中调用
 *  android 4.0以前可以正常显示overflow中的menuitem的icon
 * @param view
 * @param menu
 * @return
 */
@Override
protected boolean onPrepareOptionsPanel(View view, Menu menu) {
    setIconEnable(menu, true);//让在overflow中的menuitem的icon显示
    return super.onPrepareOptionsPanel(view, menu);
}

运行之后可以看到如下图:



有的手机有menu实体键,这个时候actionbar上将不会显示右上角的竖直的三个小点,而是按实体menu键显示menuitem,这不方便我们做统一的界面管理,这个时候可以再activity的onCreate()函数中调用以下代码

/**
 * 通过反射,设置实体menu键可用与否
 * 该方法在onCreate()中调用
 * @param enable  false:实体键不可用,会在actionbar上显示小点 
 *                true:可用,点击menu实体键才会显示menuitem
 */
public void setHasPermanentMenuKey(boolean enable){
    try {
        ViewConfiguration mconfig = ViewConfiguration.get(this);
        Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
        if(menuKeyField != null) {
            menuKeyField.setAccessible(true);
            menuKeyField.setBoolean(mconfig, enable);
        }
    } catch (Exception ex) {
    }
}


有的时候系统默认的title也就是actionbar并不能达到我们的预期,这时候我们一般采用自定义的方法,然后把系统默认的隐藏掉,而使用自己的,其实不必如此,android本身支持自定义actionBar的,只需要在activity的oncreate()函数中获取到actionbar,然后设置自己的actionbar布局就可以了如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_drawer_layout);
    ButterKnife.bind(this);

    setHasPermanentMenuKey(false);
    /*
     * ActionBar
     */
    ActionBar actionBar = getSupportActionBar();
    //设置自定义actionbar的view
    actionBar.setCustomView(R.layout.action_bar_layout);
    //设置展示的options为DISPLAY_SHOW_CUSTOM
    actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
    //设置showCustom为true
    actionBar.setDisplayShowCustomEnabled(true);
    //实例化自定义actionbar的view
    actionImageView = (ImageView) actionBar.getCustomView().findViewById(R.id.image_view);
    actionTextView = (TextView) actionBar.getCustomView().findViewById(R.id.textview);
    actionPersonalView = (TextView) actionBar.getCustomView().findViewById(R.id.personal_textview);
    actionPersonalView.setOnClickListener(this);
    actionImageView.setOnClickListener(this);

这里注意使用getSupportActionBar()的时候有些时候获取到的actionbar为null,这个时候检查是否在menifest或者代码中设置了No_title或者全屏,设置成任何一个都会导致null

这里的actionBar.setCustomView(int layout);这个就可以设置自定义actionbar布局

我的布局acdtion_bar_layout如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_vertical"
        android:src="@mipmap/ic_launcher"/>
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:textSize="20sp"
        android:text="标题" />

    <TextView
        android:id="@+id/personal_textview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="个人中心"
        android:gravity="right|center_vertical"
        android:layout_gravity="right"/>

</LinearLayout>
得到的action如下:




二、侧滑菜单Drawerlayout

该类位于

 android.support.v4.widget.DrawerLayout

使用很简单,直接在xml中使用按照规则使用即可

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.user.customviewdemo.drawerlayout.DrawerLayoutActivity">

    <!--主界面布局  主界面写在最上面-->
    <LinearLayout
        android:id="@+id/content_frame"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/textview"
            android:layout_marginTop="100dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="滑出左菜单"
            android:textSize="30sp"
            android:gravity="center"/>
        <TextView
            android:id="@+id/textview1"
            android:layout_marginTop="100dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="30sp"
            android:text="滑出右菜单"
            android:gravity="center"/>

        <ImageView
            android:id="@+id/image_view"
            android:layout_marginTop="50dp"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@mipmap/ic_launcher"
            android:scaleType="center"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>


    <!--左侧滑菜单布局 layout_gravity="start" -->
    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@android:color/holo_green_dark"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />

    <!--右侧滑菜单布局  layout_gravity="end"-->
    <RelativeLayout
        android:id="@+id/right_drawer"
        android:layout_width="220dp"
        android:layout_height="match_parent"
        android:layout_gravity="end"
        android:background="#111"
        android:gravity="center_horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="个人中心"
            android:textColor="@android:color/white"
            android:textSize="24sp" />
    </RelativeLayout>

</android.support.v4.widget.DrawerLayout>

activity中代码如下:

package com.example.user.customviewdemo.drawerlayout;

import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.user.customviewdemo.R;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import butterknife.Bind;
import butterknife.ButterKnife;

public class DrawerLayoutActivity extends AppCompatActivity implements View.OnClickListener {

    @Bind(R.id.left_drawer)
    ListView leftDrawer;
    @Bind(R.id.right_drawer)
    RelativeLayout rightDrawer;
    @Bind(R.id.drawer_layout)
    DrawerLayout drawerLayout;
    @Bind(R.id.textview)
    TextView textview;
    @Bind(R.id.textview1)
    TextView textview1;
    @Bind(R.id.image_view)
    ImageView imageView;


    private ImageView actionImageView;
    private TextView actionTextView;
    private TextView actionPersonalView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drawer_layout);
        ButterKnife.bind(this);

        setHasPermanentMenuKey(false);
        /*
         * ActionBar
         */
        ActionBar actionBar = getSupportActionBar();
        //设置自定义actionbar的view
        actionBar.setCustomView(R.layout.action_bar_layout);
        //设置展示的options为DISPLAY_SHOW_CUSTOM
        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
        //设置showCustom为true
        actionBar.setDisplayShowCustomEnabled(true);
        //实例化自定义actionbar的view
        actionImageView = (ImageView) actionBar.getCustomView().findViewById(R.id.image_view);
        actionTextView = (TextView) actionBar.getCustomView().findViewById(R.id.textview);
        actionPersonalView = (TextView) actionBar.getCustomView().findViewById(R.id.personal_textview);
        actionPersonalView.setOnClickListener(this);
        actionImageView.setOnClickListener(this);


        /**
         * 左边侧滑菜单
         */
        String[] strs = getResources().getStringArray(R.array.menu_list);
        leftDrawer.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs));

        /**
         * 主界面按钮添加监听,点击滑出菜单
         */
        textview.setOnClickListener(this);
        textview1.setOnClickListener(this);

        /**
         * drawerLayout添加监听,监听侧滑过程,包括打开,关闭,和侧滑offSet
         * ActionBarDrawerToggle继承了DrawerLayout.DrawerListener
         * 所以可以直接使用
         */
        drawerLayout.addDrawerListener(new ActionBarDrawerToggle(this, drawerLayout, R.string.hello_blank_fragment, R.string.app_name) {
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                actionTextView.setText("标题");
            }

            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                super.onDrawerSlide(drawerView, slideOffset);
                //设置actionbar中的icon和主界面的imageview旋转
                actionImageView.setRotation(slideOffset*90);
                imageView.setRotation(slideOffset*270);

            }
        });


    }

    /**
     * 通过反射,设置实体menu键可用与否
     * 该方法在onCreate()中调用
     * @param enable  false:实体键不可用,会在actionbar上显示小点
     *                true:可用,点击menu实体键才会显示menuitem
     */
    public void setHasPermanentMenuKey(boolean enable){
        try {
            ViewConfiguration mconfig = ViewConfiguration.get(this);
            Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
            if(menuKeyField != null) {
                menuKeyField.setAccessible(true);
                menuKeyField.setBoolean(mconfig, enable);
            }
        } catch (Exception ex) {
        }
    }

    /**
     *  android 4.0以后使用AppCompatActivity必须在该方法中调用setIconEnable(),
     *  隐藏的menuitem的icon才会显示
     *  android 4.0以后其他的activity可以再onPrepreOptionMenu()中调用
     *  android 4.0以前可以正常显示overflow中的menuitem的icon
     * @param view
     * @param menu
     * @return
     */
    @Override
    protected boolean onPrepareOptionsPanel(View view, Menu menu) {
        setIconEnable(menu, true);//让在overflow中的menuitem的icon显示
        return super.onPrepareOptionsPanel(view, menu);
    }

    private Menu menu;

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

        int groupId = 1;
        MenuItem item1 = menu.add(groupId, Menu.FIRST + 1, 1, "将第二组item不可见");
        item1.setIcon(R.mipmap.ic_launcher);
        menu.add(groupId, Menu.FIRST + 2, 2, "将第二组item可见");

        menu.add(groupId, Menu.FIRST + 3, 3, "将第二组item不可用");
        MenuItem item4 = menu.add(groupId, Menu.FIRST + 4, 4, "将第二组item可用");
        item4.setIcon(R.mipmap.ic_launcher);
        menu.add(groupId, Menu.FIRST + 5, 5, "将第二组item可单选");
        menu.add(groupId, Menu.FIRST + 6, 6, "将第二组item可多选");

        groupId = 2;
        MenuItem item7 = menu.add(groupId, Menu.FIRST + 7, 7, "menu2_1");
        item7.setIcon(R.mipmap.ic_launcher);
        MenuItem item8 = menu.add(groupId, Menu.FIRST + 8, 8, "menu2_2");
        item8.setIcon(R.mipmap.ic_launcher);

        SubMenu subMenu = menu.addSubMenu(groupId, Menu.FIRST + 9, 9, "sub menu");
        subMenu.add(groupId, Menu.FIRST + 10, 1, "sub1");
        subMenu.add(groupId, Menu.FIRST + 11, 2, "sub2");

        /**
         * 这个监听事件可以对item的点击事件进行拦截,拦截后的item在onOptionsItemSelected()中不会得到执行
         */
        item1.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                return true;//返回true为拦截,false不拦截
            }
        });
        return true;
    }


    /**
     * 利用反射机制调用MenuBuilder中的setOptionIconsVisable(),
     * 如果是集成自AppCompatActivity则不行,需要在onPreareOptionPanel()中调用该方法
     * @param menu   该menu实质为MenuBuilder,该类实现了Menu接口
     * @param enable enable为true时,菜单添加图标有效,enable为false时无效。因为4.0系统之后默认无效
     */
    private void setIconEnable(Menu menu, boolean enable) {
        if (menu != null) {
            try {
                Class clazz = menu.getClass();
                if (clazz.getSimpleName().equals("MenuBuilder")) {
                    Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                    m.setAccessible(true);

                    //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)
                    m.invoke(menu, enable);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case Menu.FIRST + 1:
                menu.setGroupVisible(2, false);
                break;
            case Menu.FIRST + 2:
                menu.setGroupVisible(2, true);
                break;
            case Menu.FIRST + 3:
                menu.setGroupEnabled(2, false);
                break;
            case Menu.FIRST + 4:
                menu.setGroupEnabled(2, true);
                break;
            case Menu.FIRST + 5:
                menu.setGroupCheckable(2, true, true);
                break;
            case Menu.FIRST + 6:
                menu.setGroupCheckable(2, true, false);
                break;
            case Menu.FIRST + 7:
                Toast.makeText(this, "menu2_1", Toast.LENGTH_SHORT).show();
                break;
            case Menu.FIRST + 8:
                Toast.makeText(this, "menu2_2", Toast.LENGTH_SHORT).show();
                break;
            case Menu.FIRST + 10:
                Toast.makeText(this, "sub1", Toast.LENGTH_SHORT).show();
                break;
            case Menu.FIRST + 11:
                Toast.makeText(this, "sub2", Toast.LENGTH_SHORT).show();
                break;

        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.textview:
                drawerLayout.openDrawer(leftDrawer);
                actionTextView.setText("左滑菜单");
                break;
            case R.id.textview1:
                drawerLayout.openDrawer(rightDrawer);
                actionTextView.setText("右滑菜单");
                break;
            case R.id.personal_textview:
                drawerLayout.openDrawer(rightDrawer);
                actionTextView.setText("右滑菜单");
                break;
            case R.id.image_view:
                drawerLayout.openDrawer(leftDrawer);
                actionTextView.setText("左滑菜单");
                break;
        }
    }
}

最后得到效果如下图:


怎么样,是不是感觉还是很炫的,

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值