上篇文章分析了NotesList这个Activity,并着重剖析了其中的intent机制,本文将继续上篇未完的工作,以NotesList为实例介绍Android的菜单机制(尤其是动态菜单机制)。

简介

android提供了三种菜单类型,分别为options menucontext menusub menu

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

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

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

Options Menu

Notepad中使用了options menucontext menu两种菜单。首先来看生成options menuonCreateOptionsMenu函数。

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

这是一个标准的插入一个菜单项的方法,菜单项的idMENU_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 ;
            }

      实验结果如下:



附记

感谢Evan JIANG对前一篇文章的错误之处进行指正,



只是指明会在Launcher中显示图标,同一个apk可以在桌面上加很多的图标,分别启动内部不同的多个界面。,实验后发现确实如此,学习了。

作者:
phinecos(洞庭散人)
出处:http://phinecos.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,并在文章页面明显位置给出原文连接

更多相关文章

  1. Android菜单详解(四)——使用上下文菜单ContextMenu
  2. Android中对Log日志文件的分析
  3. Android基础入门教程——2.6 菜单(Menu)
  4. Android问题(一)Android(安卓)Studio 提示"Error running app: No
  5. Android(安卓)Studio 单刷《第一行代码》系列 02 —— 日志工具
  6. Android基础入门教程——2.6 菜单(Menu)
  7. android “分享”功能的实现
  8. Android中对Log日志文件的分析
  9. Android中对Log日志文件的分析

随机推荐

  1. 腾龙娱乐公司开户17300441110
  2. php基础知识02函数
  3. ES6语法练习
  4. php基础知识01
  5. 访问php搭建的本地服务器站点时报错Synta
  6. 腾龙娱乐客服热线——I7300441110
  7. 漫画衣服怎么画褶皱简单?衣服褶皱绘画练习
  8. vue 组件化
  9. 腾龙国际开户——I7300441110
  10. 如何写出好看的C++代码