Menu

Menus是许多应用程序中的常见的用户界面组件。为了提供一个熟悉的和一致的用户体验,应该在Activity中使用menu的api来展示用户动作和其他选择。
3.0之后,安卓不在要求提供一个专用的菜单按钮,由于这个变化,安卓应用应该由传统的6个菜单面板转变为使用action bar展示通用的用户操作,所以这么说,action bar是非常重要的。
虽然一些菜单的设计和用户体验改变了,但是他们的语法定义还是以menu为基础的。


选项菜单和功能条
选项菜单是一个活动的基本菜单项,他应该放置在整个程序有影响的功能,比如搜索,邮件,和设置。
如果在Android2.3或者更低,用户可以通过点击Menu键显示菜单项。
在安卓3.0或者更高的系统,选项菜单的条目由功能条呈现,以屏幕上地动作按钮和溢出选项的组合形式。从3.0开始,菜单按钮被废弃,所以应该迁移到菜单条来提供动作的的到达和其他选项。
上下文菜单和上下文的功能模式 Context menu and contextual action mode
上下文菜单是用户长按一个元素的时候出现的悬浮菜单。他提供功能影响选择的内容或者上下文架构。
当在3.0或者以上开发的时候,应该使用上下文功能模式他触发选中内容的功能。这个模式展示影响选择内容的功能条目在屏幕的上方在一个条中,允许用户选择多个项目。
弹出菜单
一个弹出菜单以垂直列表的形式展示这些选项,挂载到触发这个菜单的view上。他有利于提供一些和指定内容相关的溢出的动作,或者为命令提供第二个部分的选项。弹出菜单的功能不应该直接影响他相关的内容,这是上下文菜单做的事情。相反,弹出菜单是为和活动中内容相关的区域提供扩展动作。
弹出菜单和上下文菜单有什么区别?


在XML中定义菜单
对所有的菜单类型,安卓提供了标准的XML格式来定义菜单项。不在活动的代码中创建菜单,应该在Xml menu resources中定义一个菜单和他所有的选项。然后可以填充这个菜单资源(加载为一个菜单对象)在活动或者碎片中。
使用菜单资源是一个好的习惯因为以下原因:
(1) 很容易在XML中看到菜单的结构
(2) 分离应用的行为代码和菜单
(3) 允许我们为不同的平台版本,屏幕大小创建替代性的菜单设置和其他配置利用app resources 架构。
创建一个菜单,在res/menu/目录下创建XML文件,使用如下元素:
<menu>
    根元素,定义菜单项的容器。必须是这个文件的根结点,可以包含多个<item> 和<group>元素。
<item>
创建一个菜单项,代表菜单中的一个选项。这个元素可能包含一个嵌套的<menu>来创建一个子菜单。
<group>
一个可选的,不可见的容器包含<item>。允许我们对菜单分类,这样就可以分享属性,比如活动状态和可见性。
下面是一个例子:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game"
          android:showAsAction="ifRoom"/>
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>
可以看到,<item>元素支持几个属性来设置一个选项的外观和行为。上面的例子展示了如下属性:


android:id
唯一的ID表示,让应用找到他
android:icon
指向一个drawable对象的引用作为菜单的图标
android:title
    标题
android:showAsAction
  指定菜单合适和如何展示位一个功能项在功能条中。   
这几个是最重要的属性,其他的,还要在学习app resource的时候在说。


可以在除子菜单的menu的item中添加一个子菜单,通过添加一个menu元素作为item的子元素。子菜单在应用有很多功能可以分类的时候,比如PC应用的菜单条(文件,编辑,视图了),下面是例子:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:title="@string/file" >
        <!-- "file" submenu -->
        <menu>
            <item android:id="@+id/create_new"
                  android:title="@string/create_new" />
            <item android:id="@+id/open"
                  android:title="@string/open" />
        </menu>
    </item>
</menu>
为了在活动中使用菜单,需要填充菜单资源(把XML资源转变成一个程序对象)使用MenuInflater.inflate.下面为告诉大家的。
创建一个选项菜单
选择菜单是包含和当前活动上下午有关的功能和其他选项的地方,比如搜索,发送邮件和设置。
这些选项出现在屏幕的位置和系统的版本有关系:
(1) 如果是2.3.x(API10)以下,菜单选项出现在屏幕的下方当按菜单按钮的时候(这个好像有印象)。下图:
(2) 如果在3.0(API11)或以上,选项菜单的选项在功能条上可用。默认系统会把所有的菜单项放在一个功能溢出条,用户可以功能条右边的溢出按钮点击打开。为了对重要功能有快速入口,可以提升一些选项出现在功能条中通过添加android:showAsAction="ifRoom"给item。


我们可以为活动或者碎片定义菜单选项。如果活动和碎片都定义了选项菜单,那么他们的UI混合。活动的选项先出现,然后碎片的以他们被添加到活动的顺序出现。如果有必要,可以通过android:orderInCategory属性,重新排列菜单项。
为了给活动指定菜单选项,需要重写onCreateOptionsMenu()(碎片有他自己的onCreateOptionsMenu()方法),在这个方法中可以填充定的XML文件为一个菜单。比如:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}


处理点击事件
当用户选中了功能菜单的一项(包括菜单条的功能项),系统调用活动的onOptionsItemSelected方法。这个方法传递一个被选中的MenuItem,可以调用getItemId来识别这个选项。方法返回菜单项的唯一ID(通过android:id属性定义或者传递给add方法的整数)。然后可以和已知的菜单选项匹配,执行合适的行为。
代码如下:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
当我们成功处理了一个菜单项返回true,但是如果没有处理菜单项,应该调用父类的实现onOptionsItemSelected()(默认返回false)
如果我们的活动包括碎片,系统首先调用活动的onOptionsItemSelected()方法,然后是碎片(按照他们被添加的顺序),知道某一个返回true或者所以的碎片都被调用了。(如果活动的返回true,碎片的还调用吗)
建议:3.0为菜单项提供了android:onClick属性,可以在menu文档继续学习。感觉也不是很有必要吧。
建议:如果应用包含多个活动和他们中的一些提供相同的选项菜单,考虑创建一个活动只实现了onCreateOptionsMenu() and onOptionsItemSelected()方法。然后,每个活动继承这个类,就可以分享同样的菜单按钮了。如果想为子类添加新的菜单,重写onCreateOptionsMenu方法。调用super.onCreateOptionsMenu(menu),这样之前的菜单还是被创建,然后通过menu.add方法添加新的菜单。
注意:add方法如果在super.onCreateOptionsMenu(menu)之前调用,新增的按钮在前面,否则在后面,还是有顺序关系的,这个要注意了哈。
在这个方法,添加
Button button  = (Button) findViewById(R.id.showContextMenu);
registerForContextMenu(button);
启动子类会报错,就是button为null,如果在onCreate中就OK,那么这个活动继承,是怎么的回事,不继承布局吗?组件不私有的?估计是不继承啊。及时把button定义成公开的成员变量也不行啊。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.my_menu, menu);
    return super.onCreateOptionsMenu(menu);
}


运行时改变菜单
系统调用onCreateOptionsMenu之后,一直保存这个实例,所以不会再调用出发菜单因为某些原因不可用,但是我们应该使用onCreateOptionsMenu仅仅初始化出菜单,在活动的整个生命周期不要改变。
如果非要变的话就在onPrepareOptionsMenu(),这个慎重吧。
Note: You should never change items in the options menu based on the View currently in focus. When in touch mode (when the user is not using a trackball or d-pad), views cannot take focus, so you should never use focus as the basis for modifying items in the options menu. If you want to provide menu items that are context-sensitive to a View, use a Context Menu.


创建上下文菜单
上下文菜单提供功能,影响UI中一个指定的选项或者上下文架构。可以为任何view提供上下文菜单,但是最常用的是ListView,GridView,或者其他用户可以直接在他们身上执行动作。
两种提供上下文动作的方法:
(1) 在一个悬浮的上下文菜单,floating context menu。当用户长按某一个view的时候,展示出一个悬浮的一些菜单。用户一次只能执行一个动作
(2) 上下文菜单模式。contextual action mode。这个模式,是ActionMode的一个系统实现,在屏幕上方展示一个上下文功能条,影响被选中的项目。当这个模式激活,用户可以一次执行多个选项(如果app允许),高级啊
上下文功能模式只在3.0以上次爱心那个,如果低于3.0,还是要退回到悬浮的上下文菜单的。
创建一个悬浮的上下文菜单
1. 通过调用registerForContentMenu为View注册上下文菜单,把view传递进去。如果活动使用ListView或者GridView,并且想为每一个项目提供上下文菜单,通过传递ListView或者GridView给registerForContentMenu为所有的项目注册。
2. 实现onCreateContextMenu方法在活动或者碎片中。当注册的view接收到一个长按时间,系统调用我们的onCreateMenu方法。通常通过实例menu资源,定义一个菜单选项。(一定要调用super.onCreateContextMenu,气死了,没有super,直接栈溢出啊)
 
MenuInflater允许我们从menu资源实例一个上下文菜单。回调方法参数包括用户选择的view和一个ContextMenu.ContextMenuInfo对象,提供选择项的额外信息。如果活动有几个view提供不同的上下文菜单,可以通过这个参数决定实例化哪个菜单。
3. 实现onContextItemSelected
当用户点击这个菜单,系统调用这个方法执行合适的动作。
@Override
public boolean onContextItemSelected(MenuItem item) {
    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
    switch (item.getItemId()) {
        case R.id.edit:
            editNote(info.id);
            return true;
        case R.id.delete:
            deleteNote(info.id);
            return true;
        default:
            return super.onContextItemSelected(item);
    }
}
   getItemId方法为被选择的菜单项查询Id(在android:id属性定义的)。
当成功处理菜单项返回true,如果不处理,传递给父类实现处理。如果活动有碎片,还是活动先调用。不处理的时候调用父类,系统把这个事件传递给每个所各自的回调方法(一次一个,按照他们被添加的顺序),直到true或者false返回(默认的活动的实现返回false,android.ap.Fragment也返回false,所以不处理应该总是交给父类处理)。


这个菜单弹出的很难看啊,怎么搞,自己的icon图片都不展示,就是一个文本,太丑了。看看强大的Mode吧。


Using the contextual action mode
上下文动作模式是一个ActionMode是系统实现,针对用户交互,执行上下文动作。
ActingMode:代表用户界面的一个上下文模式。行为方式可以用来提供替代交互方式替换正常UI的部分,直到结束。行为模式好的方式例子包括文本选择和上下文行为。
当用户通过选择一个项目触发这个模式,一个上下文功能条出现在屏幕的顶部给用户呈现他们可以在当前选择可以执行的动作。当这个模式可用,用户可以选择多个选项(如果app允许),取消选择,并且在活动中导航。当用户取消选择所有的选项,点击返回按钮,或者选择功能条左边的完成,这个行为模式不可用,上下文菜单消失。
注意:上下文功能条不是必须和功能条关联。他们独自操作,即使上下文的功能条覆盖了功能条的位置。
如果在安卓3.0以上开发,应该使用上下文功能模式呈现上下文行为,而不是悬浮的上下文菜单。
对于提供上下文功能的view,通常应该调用下面当中一个或全部来激发上下文模式。
(1) 用户长按
(2) 用户选择一个checkbox或者类似的UI组件在view中
我们自己的程序如何调用这个上下文模式,有自己定义。有两种设计:
(1) 在一个独立的,任意的view上
(2) 在ListView或者GridView上的一组选项(允许用户多选,在他们上面执行同一个行为)。
Enabling the contextual action mode for individual views
如果想在用户选择特定的view的时候激活上下文行为模式,应该
(1) 实现ActionMode.CallBack接口。在他的回调方法中,可以指定上下文功能条的行为,响应点击事件,处理其他的生命周期事件
(2) 调用startActionMode当需要展示功能条的时候(比如用户长按view)


Enabling batch contextual actions in a ListView or GridView
如果想在ListView或者GridView(或者其他AbsListView的实现),允许用户执行多个动作应该:
(1) 实现AbsListView.MultiChoiceModeListener 接口(就是创建他的一个实例,我们可以直接通过匿名函数的方式处理),通过setMultiChoiceModelListener设置到view group中。在监听器回调方法中,可以为上下文功能条指定行为,响应每个条目的单击事件,处理其他继承自ActionMode.call接口的回调
(2) 调用setChoiceMode使用CHOICE_MODE_MULTIPLE_MODAL参数。
下面这个还需要继续学习哈:比如checkbox的?
That's it. Now when the user selects an item with a long-click, the system calls the onCreateActionMode() method and displays the contextual action bar with the specified actions. While the contextual action bar is visible, users can select additional items.
In some cases in which the contextual actions provide common action items, you might want to add a checkbox or a similar UI element that allows users to select items, because they might not discover the long-click behavior. When a user selects the checkbox, you can invoke the contextual action mode by setting the respective list item to the checked state with setItemChecked().


创建一个弹出菜单
弹出菜单是一个行为菜单绑定到一个view上。出现在绑定view下面如果有空间,或者上面。他被用来:
(1) 为指定内容的行为提供一个溢出类型的菜单,注意:这和上下文菜单不一样,只影响选择的内容。如果影响选择的上下文,使用上下文的两种方式吧。
(2) 提供命令语句的第二部分(比如按钮标记为添加,弹出一个按钮,有不同的添加选项)
(3) 提供一个类似spinner的下拉,不保存一个永久的选择
注意:API11以后才可用
自己的和文档的有点差距,大体是差不多的。
public void showPopup(View v) {
        PopupMenu popup = new PopupMenu(this, v);
        MenuInflater inflater = popup.getMenuInflater();
        popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()){
                    case R.id.context1:
                        Toast.makeText(getApplicationContext(), "Pop上下文1", Toast.LENGTH_SHORT).show();
                        return true;
                    case R.id.context2:
                        Toast.makeText(getApplicationContext(),"Pop上下文2222",Toast.LENGTH_SHORT).show();
                        return  true;
                    default:
                        return false;
                }
            }
        });
        inflater.inflate(R.menu.content_menu, popup.getMenu());
        popup.show();
}


1. Instantate a PopupMenu with its constructor, which takes the current application Context and the View to which the menu should be anchored.
2. Use MenuInflater to inflate your menu resource into the Menu object returned by PopupMenu.getMenu(). On API level 14 and above, you can use PopupMenu.inflate() instead.
3. Call PopupMenu.show().
To perform an action when the user selects a menu item, you must implement the PopupMenu.OnMenuItemClickListener interface and register it with your PopupMenu by calling setOnMenuItemclickListener(). When the user selects an item, the system calls the onMenuItemClick() callback in your interface.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值