原文网址:http://kb.cnblogs.com/page/78304/

简介

  android提供了三种菜单类型,分别为options menu,context menu,sub menu。

  options menu就是通过按home键来显示,context menu需要在view上按上2s后显示。这两种menu都有可以加入子菜单,子菜单不能种不能嵌套子菜单。options menu最多只能在屏幕最下面显示6个菜单选项,称为iconmenu,icon menu不能有checkable选项。多于6的菜单项会以more icon menu来调出,称为expanded menu。options menu通过activity的onCreateOptionsMenu来生成,这个函数只会在menu第一次生成时调用。任何想改变options menu的想法只能在onPrepareOptionsMenu来实现,这个函数会在menu显示前调用。onOptionsItemSelected 用来处理选中的菜单项。

  context menu是跟某个具体的view绑定在一起,在activity种用registerForContextMenu来为某个view注册context menu。context menu在显示前都会调用onCreateContextMenu来生成menu。onContextItemSelected用来处理选中的菜单项。

  android还提供了对菜单项进行分组的功能,可以把相似功能的菜单项分成同一个组,这样就可以通过调用setGroupCheckable,setGroupEnabled,setGroupVisible来设置菜单属性,而无须单独设置。

  Options Menu

Notepad中使用了options menu和context menu两种菜单。首先来看生成options menu的onCreateOptionsMenu函数。

  menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert)
                .setShortcut('3', 'a')
                .setIcon(android.R.drawable.ic_menu_add);

  这是一个标准的插入一个菜单项的方法,菜单项的id为MENU_ITEM_INSERT。有意思的是下面这几句代码:

 Intent intent = new Intent(null, getIntent().getData());
        intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
        menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
                new ComponentName(this, NotesList.class), null, intent, 0, null);

  这到底有何用处呢?其实这是一种动态菜单技术(也有点像插件机制),若某一个activity,其类型是”android.intent.category.ALTERNATIVE”,数据是”vnd.android.cursor.dir/vnd.google.note”的话,系统就会为这个activity增加一个菜单项。在androidmanfest.xml中查看后发现,没有一个activity符合条件,所以这段代码并没有动态添加出任何一个菜单项。

  为了验证上述分析,我们可以来做一个实验,在androidmanfest.xml中进行修改,看是否会动态生成出菜单项。

  实验一

首先我们来创建一个新的activity作为目标activity,名为HelloAndroid,没有什么功能,就是显示一个界面。

public class HelloAndroid extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.main);
    }
}

  它所对应的布局界面XML文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" android:id="@+id/TextView01"/> <Button android:id="@+id/Button01" android:layout_height="wrap_content" android:layout_width="fill_parent" android:text="@string/txtInfo"></Button>
</LinearLayout>

然后修改androidmanfest.xml,加入下面这段配置,让HelloAndroid满足上述两个条件:

    <activity android:name="HelloAndroid" android:label="@string/txtInfo">
            <intent-filter>
                <action android:name="com.android.notepad.action.HELLO_TEST" />
                <category android:name="android.intent.category.ALTERNATIVE"/>
                <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
            </intent-filter>
        </activity>

  好了,运行下试试,哎,还是没有动态菜单项加入呀!怎么回事呢?查看代码后发现,原来是onPrepareOptionsMenu搞的鬼!这个函数在onCreateOptionsMenu之后运行,下面这段代码中,由于Menu.CATEGORY_ALTERNATIVE是指向同一个组,所以把onCreateOptionsMenu中设置的菜单项给覆盖掉了,而由于onPrepareOptionsMenu没有给Menu.CATEGORY_ALTERNATIVE附新值,故Menu.CATEGORY_ALTERNATIVE还是为空。

   Intent intent = new Intent(null, uri);
            intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
            menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0,items);

好的,那我们暂时把上面这几句给注释掉,当然,也可以不注释这几句,在onCreateOptionsMenu中改groupid号,即将Menu.CATEGORY_ALTERNATIVE改为Menu.first,其他的也行,但注意不要改为menu.none,这样会覆盖掉。

menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert)
                .setShortcut('3', 'a')
                .setIcon(android.R.drawable.ic_menu_add);

  添加的菜单。因为menu.none也为0。运行后就可以看到动态菜单出来了!

上面这个options menu是在NotesList界面上没有日志列表选中的情况下生成的,若先选中一个日志,然后再点”menu”,则生成的options menu是下面这样的:

哎,又动态增加了两个菜单项”Edit note”和”Edit title”,这又是如何动态加入的呢?这就是onPrepareOptionsMenu的功劳了。

    Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());

  首先获取选中的日志(若没有选择,则uri为空)

  Intent[] specifics = new Intent[1];
            specifics[0] = new Intent(Intent.ACTION_EDIT, uri);
            MenuItem[] items = new MenuItem[1];

然后为选中的日志创建一个intent,操作类型为Intent.ACTION_EDIT,数据为选中日志的URI.于是会为选中的日志创建一个”Edit note”菜单项。

 Intent intent = new Intent(null, uri);
            intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
            menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0,
                    items);

这几句和上面onCreateOptionsMenu函数中类似,用于动态增加菜单项,若某一个activity,其类型是”android.intent.category.ALTERNATIVE”,数据是”vnd.android.cursor.item/vnd.google.note”的话,系统就会为这个activity增加一个菜单项。在androidmanfest.xml中查看后发现,TitleEditor这个activity符合条件,于是系统就为TitleEditor这个activity动态添加一个菜单项”Edit title”。

else {
            menu.removeGroup(Menu.CATEGORY_ALTERNATIVE);
        }

  若日志列表为空,则从菜单中删除组号为Menu.CATEGORY_ALTERNATIVE的菜单项,只剩下”Add note”菜单项。

  处理“选中菜单项”事件

  菜单项选中事件的处理非常简单,通过onOptionsItemSelected来完成,这里只是简单地调用 startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));这个intent的操作类型为Intent.ACTION_INSERT,数据为日志列表的URI,即”content:// com.google.provider.NotePad/notes”

     @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case MENU_ITEM_INSERT:
            // Launch activity to insert a new item
            startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

  Context Menu

  下面介绍另一种菜单---上下文菜单,这通过重载onCreateContextMenu函数实现。首先确认已经选中了日志列表中的一个日志,若没选择,则直接返回。Cursor指向选中的日志项。

   Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
        if (cursor == null) {
            // For some reason the requested item isn't available, do nothing
            return;
        }

  然后,设置上下文菜单的标题为日志标题

        // Setup the menu header
        menu.setHeaderTitle(cursor.getString(COLUMN_INDEX_TITLE));

最后为上下文菜单增加一个菜单项

        // Add a menu item to delete the note
        menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_delete);

   对于上下文菜单项选中的事件处理,是通过重载onContextItemSelected实现的。

        switch (item.getItemId()) {
            case MENU_ITEM_DELETE: {
                // Delete the note that the context menu is for
                Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id);
                getContentResolver().delete(noteUri, null, null);
                return true;
            }
        }
        return false;
}

  对于日志的删除,首先调用ContentUris.withAppendedId(getIntent().getData(), info.id);来拼接出待删除日志的URI.然后getContentResolver().delete(noteUri, null, null);调用下层的Content Provider去删除此日志。

  实验二

   来做个简单实验,在上述代码基础上增加一个上下文菜单项。首先在onCreateContextMenu函数中增加一个上下文菜单项:

menu.add(0,MENU_ITEM_INSERT,0,R.string.menu_insert);

然后为其在onContextItemSelected函数中增加一个处理过程:

case MENU_ITEM_INSERT:
            {
                new AlertDialog.Builder(this).setIcon(R.drawable.app_notes)
                .setTitle(R.string.app_name).setMessage(R.string.error_message).setPositiveButton(R.string.button_ok, new OnClickListener(){                     public void onClick(DialogInterface dialog, int which) {
                        // TODO Auto-generated method stub
                        
                    }
   
                }).show();
                return true;
            }

实验结果如下:

【转】Android实例剖析笔记(二)--用实例讲解Andriod的开发过程,以NotesList为实例介绍Android的菜单机制的更多相关文章

  1. Android实例剖析笔记(二)

    摘要:用实例讲解Andriod的开发过程,以NotesList为实例介绍Android的菜单机制 简介 android提供了三种菜单类型,分别为options menu,context menu,su ...

  2. Android实例剖析笔记(四)

    摘要:分析NoteEditor这个类和以及Content Provider机制 NoteEditor深入分析 首先来弄清楚“日志编辑“的状态转换,通过上篇文章的方法来做下面这样一个实验,首先进入“日志 ...

  3. Android实例剖析笔记(一)

    摘要:用实例讲解Andriod的开发过程 开卷语 俗话说,“熟读唐诗三百首,不会作诗也会吟”.最近收集了很多Android的示例代码,从这些代码的阅读和实验中学习到很多知识,从而产生写这个系列的打算, ...

  4. Android实例剖析笔记(三)

    摘要:点介绍Activity的生命周期,通过一个简单的实验来摸索状态转换的机制 Activity的生命周期 Activity类中有许多onXXX形式的函数可以重载,比如onCreate,onStart ...

  5. Android Studio 学习笔记(二):布局简介和xmlns说明

    初学Android Studio,是在b站看的教程视频,这里的笔记也是以其为基础的,个人强烈安利: [天哥]Android开发视频教程最新版 Android Studio开发 Android 布局简介 ...

  6. Android Fragment学习笔记(二)----Fragment界面添加和管理

    Fragment界面添加 了解过fragment的生命周期等简单知识,于是去看官方文档来了解更多相关内容,要添加fragment到我们的UI界面中,给出了两种常用的方法,第一个是在activity的布 ...

  7. 【Android开发学习笔记】【第一课】初识New Project,工程文件介绍

    初学者新建一个Andriod工程后,往往不知道Pakage Explorer区域的每个文件是什么作用,今天学习了一下,自我总结一下. 1.先新建一个工程 2.输入名称,以及支持的SDK版本等(这些可以 ...

  8. Android学习路线(二十四)ActionBar Fragment运用最佳实践

    转载请注明出处:http://blog.csdn.net/sweetvvck/article/details/38645297 通过前面的几篇博客.大家看到了Google是怎样解释action bar ...

  9. Android:日常学习笔记(7)———探究UI开发(4)

    Android:日常学习笔记(7)———探究UI开发(4) UI概述  View 和 ViewGrou Android 应用中的所有用户界面元素都是使用 View 和 ViewGroup 对象构建而成 ...

随机推荐

  1. linux中history命令使用与配置

    history中设置显示命令的执行时间 vi /root/.bashrc HISTTIMEFORMAT="%Y-%M-%D %H:%M:%S" export HISTTIMEFOR ...

  2. php 多维数组转换

    把字符类型转换成时间类型的,先用foreach遍历出来时间,在通过时间函数转换成时间格式; 例子: <?phpecho "<pre>";$lsrfield = a ...

  3. 关于URL 解码, 编码

    由于近期客户需要用到CA认证,此CA认证采用的是URL方式出传值 使用指定的编码对象将 URL 编码的字符串转换为已解码的字符串. 编码个人理解就是将某字符串以某种方式储存起来,而解码则以其编码格式得 ...

  4. 服务器证书安装配置指南(IIS7.5) 分类: ASP.NET 2014-11-05 12:39 105人阅读 评论(0) 收藏

    1.启动IIS管理器,点击开始菜单->所有程序->管理工具->Internet信息服务(IIS)管理器: 2.选择"服务器证书": 3.在右边窗口,选择" ...

  5. Tomcat- java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServlet

    在MyEclipse中启动Tomcat的时候报错: java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServ ...

  6. There is no ID/IDREF binding for IDREF

    http://blog.csdn.net/greensurfer/article/details/7596219

  7. metalink下载补丁包

    以下截图 截取自 某 升级包中携带的 readme文档 把以上图片转换为 文字 Download and Install Patch Updates Refer to the My Oracle Su ...

  8. 介绍TableView非常不错的一篇文章

    原文:http://blog.csdn.net/fanxiaochuan/article/details/11332775 介绍TableView非常不错的一篇文章: http://www.cocoa ...

  9. VisualStudio2015内置LocalDB

    简直坑爹,我将之前的VS2013的工程迁移到新电脑的VS2015,然后用的本地数据库居然连接报错了,然后我试连了一下本地数据库, 就是Tools-->Connect to Databases-- ...

  10. csv文本编辑引号问题

    今天发现一个csv的一个问题,csv工具类对于引号默认有特殊的处理.我希望写出来的结果是 1,"1",1 原来的代码是 CsvWriter cw=new CsvWriter(&qu ...