Android UI开发第二十四篇——Action Bar

 

Android UI开发第二十四篇——Action Bar 

标签: ActionBarandroidfragmentmenuhtml

2012-10-31 16:11 143916人阅读 评论(29) 收藏 举报java

 分类:android

 

上图中:api

  1. logo安全

  2. title网络

  3. iconapp

目录(?)[+]框架


             Action bar是一个标识应用程序和用户位置的窗口功能,而且给用户提供操做和导航模式。在大多数的状况下,当你须要突出展示用户行为或全局导航的activity中使用action bar,由于action bar可以使应用程序给用户提供一致的界面,而且系统可以很好根据不一样的屏幕配置来适应操做栏的外观。你可以用ActionBar的对象的API来控制操做栏的行为和可见性,这些API被添加在Android3.0(API 级别 11)中。ide

      Action bar的主要目的是:
svg

        1.  提供一个用于识别应用程序的标示和用户的位置的专用空间。

         这个空间的左边是应用的图标或logo,以及Activity的标题。可是,若是是像当前选择的标签这样的标识当前View对象的导航标签,你能够选择删除Activity的标题。

        2.  在不一样的应用程序之间提供一致的导航和视觉体验。

        Action bar提供了用于Fragment间切换的内置导航标签。它还提供了一个用于替换导航模式或优化当前视觉效果(如按照不一样条件排序的列表)的下拉列表。

        3.  突出Activity的关键操做(如“搜索”、“建立”、“共享”等),而且在可预见的方法内给用户提供快捷的访问。

       对于关键的用户操做,你可以经过把选项菜单项做为操做项直接放到操做栏中,从而提供快捷的访问。操做项目还能提供一个操做窗口,这个窗口给更直接的操做行为提供一个嵌入的窗口部件。没有改进成操做项的菜单项在溢出菜单中仍是有效的,用户既可使用设备上的菜单按钮(设备上有按钮的时候),也可使用操做栏中的溢出菜单按钮(当设备上不包含菜单按钮时)来显示这些操做项目。

       上面的总结一下:Action bar就是替换3.0之前的tittle bar和menu。

             

        图1. Honeycomb Gallery应用中的操做栏,从左边开始,依次是logo、导航选项标签和操做项(在右边插入的一个悬浮菜单按钮)。

         Note: If you're looking for information about the contextual action bar for displaying contextual action items, see the Menu guide.

        Action Bar Design   For design guidelines, read Android Design's Action Bar guide.


添加Action Bar

       从Android3.0(API级别 11)开始,Action bar被包含在全部的使用Theme.Hole主题的Activity(或者是这些Activity的子类)中,当targetSdkVersion或minSdkVersion属性被设置为“11”或更大的数值是,这个主题是默认的主题一。如:

[html] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. <manifest ... >  

  2.     <uses-sdk android:minSdkVersion="4"  

  3.               android:targetSdkVersion="11" />  

  4.     ...  

  5. </manifest>  


       在这个例子中,应用程序要求最小的API版本级别是4(Android 1.6),可是它还要求了目标API版本级别是11(Android 3.0)。这样,当应用程序运行在Android3.0或更高的版本上时,系统就会给每一个Activity应用holographic  主题,这样,每一个Activity就会包含Action bar。

        若是你想使用ActionBar API来进行添加导航模式和修改操做栏样式的操做,你应该把minSdkVersion属性设置为“11”或更大的值。有一些方法可使你的应用支持更旧的Android版本,同时在API等级为11或更高的API等级的机器的使你的应用支持一些Action bar apis。为了保持后向兼容,请参考边框内的内容(边框内容以下)。

Remaining backward-compatible

If you want to provide an action bar in your application and remain compatible with versions of Android older than 3.0, you need to create the action bar in your activity's layout (because theActionBar class is not available on older versions).

To help you, the Action Bar Compatibility sample app provides an API layer and action bar layout that allows your app to use some of theActionBar APIs and also support older versions of Android by replacing the traditional title bar with a custom action bar layout.

删除Action bar

      若是你不想要Action bar,把Activity的主题设置为Theme.Holo.NoActionBar就能够了,如:

[html] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. <activity android:theme="@android :style/Theme.Holo.NoActionBar">  

         或者使用Action bar的 hide()方法,以下:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. ActionBar actionBar = getActionBar();  

  2. actionBar.hide();  

       当Action bar隐藏时,系统会调整你的Activity来填充当前有效的屏幕空间。你可以使用show()方法来再次显示操做栏。

      在隐藏和删除Action bar时,要小心为了适应被Action bar占用的空间而致使的Activity的从新布局。若是你的Activity有规律的隐藏和显示Action bar,你可能想要使用覆盖模式。覆盖模式在Activity的顶部描画操做栏,而不是在它们所拥有的屏幕的区域。这样,在Action bar隐藏和从新显示时,你的布局保持不变。要使用覆盖模式,就要给Activity建立一个主题,而且把android:windowActionBarOverlay属性设置为true。

       提示:若是你有一个删除了Action bar的定制化的Activity主题,它把android:windowActionBar样式属性设置为false。可是,若是你使用了删除Action bar的一个主题,那么,建立窗口将不容许Action bar再显示,所以,你不能在之后给这个Activity添加Action bar---由于getActionBar()方法将返回null。


添加操做项

       有些时候,你可能想要让用户直接访问选项菜单中的一个项目,所以你要把应该在Action bar中显示的菜单项做为一个操做项来声明。操做项可以可以包含一个图标或文本标题。若是一个菜单项不做为一个操做项显示,那么系统就会把它放到悬浮菜单中。悬浮菜单既能够经过设备的Menu按钮来显示,也能够在Action bar中一个额外的按钮来显示。

       当Activity首次启动时,系统会调用onCreateOptionsMenu()方法给你的Activity组装Action bar和悬浮菜单。在这个回调方法中应该加载在XML文件中定义的菜单项资源,如:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. @Override  

  2. public boolean onCreateOptionsMenu(Menu menu) {  

  3.     MenuInflater inflater = getMenuInflater();  

  4.     inflater.inflate(R.menu.main_activity, menu);  

  5.     return true;  

  6. }  


             

         图2. 带有图标和文本标题的两个操做项,和悬浮菜单按钮。

       在XML文件中,你可以经过给<item>元素声明android:showAsAction=”ifRoom”属性,请求把一个菜单项做为一个操做项来显示。用这种方式,只在有有效的空间时,菜单项才能显示在Action bar中。若是没有足够的空间,这个菜单项会显示在悬浮菜单中。

        若是你的菜单项支持标题和图标---带有android:title和android:icon属性---那么默认状况下,操做项仅显示图标。若是你要显示文本标题,就要给android:showAsAction属性添加withText设置,如:

  

[html] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. <?xml version="1.0" encoding="utf-8"?>  

  2. <menu xmlns:android="http://schemas.android.com/apk/res/android">  

  3.     <item android:id="@+id/menu_save"  

  4.           android:icon="@drawable/ic_menu_save"  

  5.           android:title="@string/menu_save"  

  6.           android:showAsAction="ifRoom|withText" />  

  7. </menu>  

提示:withText值示意Action bar要显示文本标题。Action bar会尽量的显示这个标题,可是,若是图标有效而且受到Action bar空间的限制,文本标题有可能显示不全。

当用户选择了一个操做项时,Activity会接收一个onOptionsItemSelected()的回调,要把android:id属性支持的ID传递给这个方法。

给每一个菜单项定义android:title属性是相当重要的,即便你没有给操做项声明标题。缘由以下:

1.  若是Action bar中没有足够的空间来显示操做项,那么菜单项就会显示在悬浮菜单中,并仅显示标题;

2.  屏幕阅读器要给视障用户朗读菜单项标题;

3.  若是仅用图标来显示操做项,那么,用户可以长按这个项目,用操做项的标题来显示提示信息。

注意:若是你添加源于Fragment对象的菜单项,那么经过Fragment类的onCreateOptionsMenu onCreateOptionsMenu回调方法,当用户选择其中一个Fragment菜单项时,系统会对用那个Fragment对象对应的onOptionsItemSelected()方法。可是,Activity有机会首先处理这个事件,由于系统在调用对应的Fragment对象的onOptionsItemSelected()方法以前会调用Activity的相同的回调方法。

       你也可以声明一个菜单项,让它始终做为操做项来显示,而不是在空间不足时就放到悬浮菜单中。大多数状况下,你不该该使用always属性值来强制一个菜单项始终显示在操做栏中,可是,当提供了一个不给悬浮菜单提供默认操做的操做窗口时,你就须要始终显示一个菜单项。可是要警戒,太多的操做项会建立一个混乱的UI,而且会致使窄屏设备上的布局问题。最好的方法是使用ifRoom属性值,它容许系统在操做栏空间不足的时候,把菜单项移到悬浮菜单中。

选择操做项:

       经过评估一些关键的特性,你应该仔细的选择选项菜单中的那些菜单项应该做为操做项来显示,一般,每一个操做项应该至少知足下列特性之一:

        1.  常用:用户百分之七十以上的访问都须要使用的操做,或者是要连续的屡次使用的操做。

        2.  重要:它是一个用户可以很容易找到的操做,即便它不是常常性的操做,也须要用户在须要的时候可以轻易的找到它,并执行。

             如,Wi-Fi设置中的添加网络等。

        3.  典型:它是一些相似应用程序的操做栏中提供的典型操做,所以,用户都指望在操做栏中可以找到它。

            如,电子邮件或社交应用程序中的“刷新”操做。

        若是你想要把四个以上的菜单项调整为操做项,那么你就应该认真考虑一下他们相对的重要性级别,而且尝试不要超过四个以上的操做项设置(而且还有使用“ifRoom”属性值的设置,容许系统在遇到空间受限的比较小的屏幕的时候,可以把靠后的操做项放到悬浮菜单中)。即便在一些宽屏设备上,空间充足,你也不该该建立不少操做项,这样会扰乱UI的布局,并且更像一个桌面工具栏,所以要保持最小数量的操做项。

       另外,如下操做应该永远不要做为操做项来显示:设置、帮助、意见反馈、或相似的操做。要把它们始终保留在悬浮菜单中。

       注意:不是全部的设备都给检索提供了专有的硬件按钮,所以,若是是你应用程序中的一个重要功能,它应该始终做为一个操做项来显示(并且一般要把放到第一项的位置,尤为是操做窗口中提供这个操做的时候)。

使用分离式操做栏

        当你的应用程序正在Android4.0(API 级别 14)或以上的版本上运行,那么还有一种叫作“分隔操做栏”的额外模式对action bar有效。当你启用分隔操做栏模式时,在屏幕的底部会显示一个独立的横条,用于显示Activity在窄屏设备(如竖屏手机)上运行时的全部操做项。

       把action bar分隔成独立的操做项,确保在窄屏设备上有合适的空间来显示全部的操做项,同时把导航条和标题元素留在顶部。

       要启用分离式操做栏,只需简单的在<application>或<activity>元素中添加uiOptions=”splitActionBarWhenNarrow”属性设置就能够了。

       要注意,Android会基于当前屏幕的尺寸用各类方式来调整操做栏的外观。使用分离式操做栏只是你可以启用的容许操做栏针对不一样屏幕尺寸来进一步优化用户体验的选项之一。你还能够容许操做栏把导航选项标签折叠到主操做栏中,若是你在操做栏中使用导航选项标签,那么一旦操做项在窄屏设备上被分离,这些导航选项标签就可能填充到主操做栏中,而不是被分离到堆叠起来的操做栏。尤为是若是你禁用了操做栏的图标和标题(用setDisplayShowHomeEnabled(false)setDisplayShowTitleEnabled(false)方法),那么导航选项标签就会折叠到主操做栏中,以下图3中第二个设备的显示:

                       

图3. 左侧是带有导航选项标签的分离式操做栏,右侧是禁用了应用图标和标题的分离式操做栏。

注意:尽管android:uiOptions属性在Android4.0(API 级别 14)中才被添加,可是为了保持跟Android的低版本的兼容性,即便你的minSdkVersion属性值小于14,那么你的应用程序也能够安全的包含android:uiOptions属性。在旧版本上运行时,由于系统不能理解这个属性,因此只是简单的忽略了这个XML属性。在你的清单文件中包含这个属性的惟一条件是,你必须在支持API级别14或更高以上版本的平台上编译你的应用程序。为了保持兼容性,你不能在你的应用程序代码中使用由minSdkVersion属性声明的版本所不支持的API,只有XML属性才能被旧的平台版本安全的忽略。

导航栏使用应用图标

       默认状况下,应用程序图标显示在操做栏的左边。你可以把这个图标当作操做项来使用。应用程序应该在这个图标上响应如下两个操做之一:

       1.  返回应用程序的“主”Activity;

       2.  向应用程序上级页面导航。

       当用户触摸这个图标时,系统会调用Activity带有android.R.id.home ID的onOptionsItemSelected()方法。在这个响应中,你既能够启动主Activity,也能够返回你的应用程序结构化层次中用户上一步操做的界面。

       若是你要经过应用程序图标的响应来返回主Activity,那么就应该在Itent对象中包括FLAG_ACTIVITY_CLEAR_TOP标识。用这个标记,若是你要启动的Activity在当前任务中已经存在,那么,堆栈中这个Activity之上的全部的Activity都有被销毁,而且把这个Activity显示给用户。添加这个标识每每是重要的,由于返回主Activity至关与一个回退的动做,所以一般不该该再建立一个新的主Activity的实例,不然,最终可能会在当前任务中产生一个很长的拥有多个主Activity的堆栈。

例如,下例的onOptionsItemSelected()方法实现了返回应用程序的主Activity的操做:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. @Override  

  2. public boolean onOptionsItemSelected(MenuItem item) {  

  3.     switch (item.getItemId()) {  

  4.         case android.R.id.home:  

  5.             // app icon in action bar clicked; go home  

  6.             Intent intent = new Intent(this, HomeActivity.class);  

  7.             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  

  8.             startActivity(intent);  

  9.             return true;  

  10.         default:  

  11.             return super.onOptionsItemSelected(item);  

  12.     }  

  13. }  

       在用户从另外一个应用程序进入当前Activity的状况下,你可能还想要添加FLAG_ACTIVITY_NEW_TASK标识。这个标识确保在用户返回主页或上级页面时,新的Activity不会被添加到当前的任务中,而是在属于你本身的应用程序的任务中启动。例如,若是用户经过被另外一个应用程序调用的Intent对象启动了你的应用程序中的一个Activity,那么选择操做栏图标来返回主页或上级页面时,FLAG_ACTIVITY_CLEAR_TOP标识会在属于你的应用程序的任务中启动这个Activity(不是当前任务)。系统既能够用这个新的Activity作根Activity来启动一个新的任务,也能够把存在后台的拥有这个Activity实例的一个既存任务带到前台来,而且目标Activity会接受onNewIntent()回调。所以,若是你的Activity要接收另外一个应用程序的Intent对象,那么一般应该给这个Intent对象添加FLAG_ACTIVITY_NEW_TASK标识,如:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);  


注意:若是你要使用应用图标来返回主页,要注意从Android4.0(API 级别 14)开始,必须经过调用setHomeButtonEnabled(true)方法确保这个图标可以做为一个操做项(在之前的版本,默认状况下,这个图标就可以做为一个操做项)。

向应用程序上级页面导航

       做为传统的回退导航(把用户带回任务历史中的前一个窗口)的补充,你可以让action bar图标提供向上级页面导航的功能,它应用把用户带回到你的应用程序的上级页面。例如,当前页面时你的应用程序层次比较深的一个页面,触摸应用程序图标应该返回返回上一级页面(当前页面的父页面)。

          

         图4. Email应用程序的标准图标(左)和向上导航图标(右)。系统会自动添加向上指示。

       例如,图5演示了当用户从一个应用程序导航到一个属于不一样应用程序的Activity时,“回退”按钮的行为。

            

       可是,若是在编辑完邮件以后,想要停留在Email应用程序中,那么向上导航就容许你把用户导航到Email应用程序中编辑邮件页面的上级页面,而不是返回到前一个Activity。图6演示了这种场景,在这个场景中,用户进入到Email应用程序后,不是按回退按钮,而是按操做栏图标来向上导航。

       

         图6. 从People应用进入Email应用后,向上导航的行为。

         要是应用程序图标可以向上导航,就要在你的ActionBar中调用SetDisplayHomeAsUpEnabledtrue(true)方法。

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. protected void onCreate(Bundle savedInstanceState) {  

  2.     super.onCreate(savedInstanceState);  

  3.   

  4.     setContentView(R.layout.main);  

  5.     ActionBar actionBar = getActionBar();  

  6.     actionBar.setDisplayHomeAsUpEnabled(true);  

  7.     ...  

  8. }  


       当用户触摸这个图标时,系统会调用带有android.R.id.home ID的onOptionsItemSelected()方法。

       请记住要在Intent对象中使用FLAG_ACTIVITY_CLEAR_TOP标识,以便你不会这个父Activity存在的状况下,再建立一个新的实例。例如,若是你不使用FLAG_ACTIVITY_CLEAR_TOP标识,那么向上导航后,再按回退按钮,实际上会把用户带到应用程序的下级页面,这是很奇怪的。

注意:若是有不少用户可以到达应用程序中当前Activity的路径,那么,向上图标应该沿着当前Activity的实际启动路径逐步的向会导航。

添加操做视窗

       操做视窗是做为操做项目按钮的替代品显示在操做栏中的一个可视构件。例如,若是你有一个用于搜索的可选菜单项,你能够用SearchView类来替代操做栏上的搜索按钮,如图7所示:

             

       图7. 折叠(上)和展开(下)的搜索视窗的操做栏

       要个菜单资源中的一个项目声明一个操做视窗,你既可使用android:actionLayout属性也android:actionViewClass属性来分别指定一个布局资源或要使用的可视构件类。例如:

[html] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. <?xml version="1.0" encoding="utf-8"?>  

  2. <menu xmlns:android="http://schemas.android.com/apk/res/android">  

  3.     <item android:id="@+id/menu_search"  

  4.           android:title="@string/menu_search"  

  5.           android:icon="@drawable/ic_menu_search"  

  6.           android:showAsAction="ifRoom|collapseActionView"  

  7.           android:actionViewClass="android.widget.SearchView" />  

  8. </menu>  

        android:showAsAction属性也可包含“collapseActionView”属性值,这个值是可选的,而且声明了这个操做视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操做视窗展开。不然,这个操做视窗在默认的状况下是可见的,而且即使在用于不适用的时候,也要占据操做栏的有效空间。

       若是须要给操做视窗添加一些事件,那么就须要在onCreateOptionsMenu()回调执行期间作这件事。你可以经过调用带有菜单项ID的findItem()方法来获取菜单项,而后再调用getActionView()方操做视窗中的元素。例如,使用如下方法获取上例中的搜索视窗构件。

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. @Override  

  2. public boolean onCreateOptionsMenu(Menu menu) {  

  3.     getMenuInflater().inflate(R.menu.options, menu);  

  4.     SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();  

  5.     // Configure the search info and add any event listeners  

  6.     ...  

  7.     return super.onCreateOptionsMenu(menu);  

  8. }  

处理可折叠的操做视窗

        操做视窗让你在不改变Activity或Fragment的状况下,就能够给用户提供快捷的访问和丰富的操做。可是,默认状况下让操做视窗可见可能不太合适。要保证操做栏的空间(尤为是在小屏幕设备上运行时),你可以把操做视窗折叠进一个操做项按钮中。当用户选择这个按钮时,操做视窗就在操做栏中显示。被折叠的时候,若是你定义了android:showAsAction=”ifRoom”属性,那么系统可能会把这个项目放到溢出菜单中,可是当用户选项了这个菜单项,它依然会显示在操做栏中。经过给android:showAsAction属性添加“collapseActionView”属性值,你可以让操做视窗能够折叠起来。

        由于在用户选择这个项目时,系统会展开这个操做视窗,因此你没必要要在onOptionsItemSelected()回调方法中响应这个菜单项。在用户选择这个菜单项时,系统会依然调用onOptionsItemSelected()方法,可是除非你在方法中返回了true(指示你已经替代系统处理了这个事件),不然系统会始终展开这个操做视窗。

       当用户选择了操做栏中的“向上”图标或按下了回退按钮时,系统也会把操做视窗折叠起来。

若是须要,你可以在代码中经过在expandActionView()和collapseActionView()方法来展开或折叠操做视窗。

       注意:尽管把操做视窗折叠起来是可选的,可是,若是包含了SearchView对象,咱们推荐你始终把这个视窗折叠起来,只有在须要的时候,由用户选择后才把它给展开。在提供了专用的“搜索”按钮的设备上也要当心了,若是用户按下了“搜索”按钮,那么也应该把这个搜索视窗给展开,简单的重写Activity的onKeyUp()回调方法,监听KEYCODE_SEARCH类型的按键事件,而后调用expandActionView()方法,就能够把操做视窗给展开。

若是你须要根据操做视窗的可见性来更新你的Activity,那么你能够定义一个OnActionExpandListener事件,而且用setOnActionExpandListener()方法来注册这个事件,而后就可以在操做视窗展开和折叠时接受这个回调方法了,如:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. @Override  

  2. public boolean onCreateOptionsMenu(Menu menu) {  

  3.     getMenuInflater().inflate(R.menu.options, menu);  

  4.     MenuItem menuItem = menu.findItem(R.id.actionItem);  

  5.     ...  

  6.   

  7.     menuItem.setOnActionExpandListener(new OnActionExpandListener() {  

  8.         @Override  

  9.         public boolean onMenuItemActionCollapse(MenuItem item) {  

  10.             // Do something when collapsed  

  11.             return true;  // Return true to collapse action view  

  12.         }  

  13.   

  14.         @Override  

  15.         public boolean onMenuItemActionExpand(MenuItem item) {  

  16.             // Do something when expanded  

  17.             return true;  // Return true to expand action view  

  18.         }  

  19.     });  

  20. }  


添加一个操做提供器

       与操做视窗相似,操做提供器(由ActionProvider类定义的)用一个定制的布局代替一个操做项目,它还须要对全部这些项目行为的控制。当你在操做栏中给一个菜单项声明一个操做项目时,它不只要一个定制的布局来控制这个菜单项的外观,并且当它在显示在溢出菜单中时,还要处理它的默认事件。不管是在操做栏中仍是在溢出菜单中,它都可以提供一个子菜单。

       例如,ActionProvider的扩展类ShareActionProvider,它经过在操做栏中显示一个有效的共享目标列表来方便共享操做。与使用传统的调用ACTION_SEND类型Intent对象的操做项不一样,你可以声明一个ShareActionProvider对象来处理一个操做项。这种操做提供器会保留一个带有处理ACTION_SEND类型Intent对象的应用程序的下拉列表,即便这个菜单项显示在溢出菜单中。所以,当你使用像这样的操做提供器时,你没必要处理有关这个菜单项的用户事件。

要给一个操做项声明一个操做提供器,就要在菜单资源中对应的<item>元素中定义android:actionProviderClass属性,提供器要使用完整的类名。例如:

[html] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. <?xml version="1.0" encoding="utf-8"?>  

  2. <menu xmlns:android="http://schemas.android.com/apk/res/android">  

  3.     <item android:id="@+id/menu_share"  

  4.           android:title="@string/share"  

  5.           android:showAsAction="ifRoom"  

  6.           android:actionProviderClass="android.widget.ShareActionProvider" />  

  7.     ...  

  8. </menu>  


       在这个例子中,用ShareActionProvider类做为操做提供器,在这里,操做提供器须要菜单项的控制,并处理它们在操做栏中的外观和行为以及在溢出菜单中的行为。你必须依然给这个菜单项提供一个用于溢出菜单的文本标题。

尽管操做提供器提供了它在溢出菜单中显示时所能执行的默认操做,可是Activity(或Fragment)也可以经过处理来自onOptionsItemSelected()回调方法的点击事件来重写这个默认操做。若是你不在这个回调方法中处理点击事件,那么操做提供器会接收onPerformDefaultAction()回调来处理事件。可是,若是操做提供器提供了一个子菜单,那么Activity将不会接收onOptionsItemSelected()回调,由于子菜单的显示替代了选择时调用的默认菜单行为。

使用ShareActionProvider类

       若是你想要在操做栏中提供一个“共享”操做,以充分利用安装在设备上的其余应用程序(如,把一张图片共享给消息或社交应用程序使用),那么使用ShareActionProvider类是一个有效的方法,而不是添加一个调用ACTION_SEND类型Intent对象的操做项。当你给一个操做项使用ShareActionProvider类时,它会呈现一个带有可以处理ACTION_SEND类型Intent对象的应用程序的下拉列表(如图8所示)。

                

        图8. Gallery 应用截屏,用ShareActionProvider对象展开显示共享目标。

        建立子菜单的全部逻辑,包括共享目标的封装、点击事件的处理(包在溢出菜单中的项目显示)等,都在ShareActionProvider类中实现了---你须要编写的惟一的代码是给对应的菜单项声明操做提供器,并指定共享的Intent对象。

        默认状况,ShareActionProvider对象会基于用户的使用频率来保留共享目标的排列顺序。使用频率高的目标应用程序会显示在下来列表的上面,而且最经常使用的目标会做为默认共享目标直接显示在操做栏。默认状况下,排序信息被保存在由DEFAULT_SHARE_HISTORY_FILE_NAME指定名称的私有文件中。若是你只使用一种操做类型ShareActionProvider类或它的一个子类,那么你应该继续使用这个默认的历史文件,而不须要作任何事情。可是,若是你使用了不一样类型的多个操做的ShareActionProvider类或它的一个子类,那么为了保持它们本身的历史,每种ShareActionProvider类都应该指定它们本身的历史文件。给每种ShareActionProvider类指定不一样的历史文件,就要调用setShareHistoryFileName()方法,而且提供一个XML文件的名字(如,custom_share_history.xml)

        注意:尽管ShareActionProvider类是基于使用频率来排列共享目标的,可是这种行为是可扩展的,而且ShareActionProvider类的扩展可以基于历史文件执行不一样的行为和排序。

        要添加ShareActionProvider对象,只需简单的给android.actionProviderClass属性设定android.widget.ShareActionProvider属性值就能够了。惟一要作的事情是定义你要用于共享的Intent对象,你必须先调用getActionProvider()方法来获取跟菜单项匹配的ShareActionProvider对象,而后调用setShareIntent()方法。

      若是对于共享的Intent对象的格式依赖与被选择的菜单项,或其余的在Activity生存周期内改变的变量,那么你应该把ShareActionProvider对象保存在一个成员属性里,并在须要的时候调用setShareIntent()方法来更新它。如:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. private ShareActionProvider mShareActionProvider;  

  2. ...  

  3.   

  4. @Override  

  5. public boolean onCreateOptionsMenu(Menu menu) {  

  6.     mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share).getActionProvider();  

  7.   

  8.     // If you use more than one ShareActionProvider, each for a different action,  

  9.     // use the following line to specify a unique history file for each one.  

  10.     // mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");  

  11.   

  12.     // Set the default share intent  

  13.     mShareActionProvider.setShareIntent(getDefaultShareIntent());  

  14.   

  15.     return true;  

  16. }  

  17. // When you need to update the share intent somewhere else in the app, call  

  18. // mShareActionProvider.setShareIntent()  

       上例中ShareActionProvider对象处理全部的跟这个菜单项有关的用户交互,而且不须要处理来自onOptionsItemSelected()回调方法的点击事件。

建立一个自定义的操做提供器

       当你想要建立一个有动态行为和在悬浮菜单中有默认图标的操做视窗时,继承ActionProvider类来定义这些行为是一个比好的的方案。建立本身的操做提供器,提供一个有组织的可重用的组件,而不是在Fragment或Activity的代码中处理各类操做项的变换和行为。

       要建立本身的操做提供器,只需简单的继承ActionProvider类,而且实现合适的回调方法。你应该实现如下重要的回调方法:

ActionProvider()

        这个构造器把应用程序的Context对象传递个操做提供器,你应该把它保存在一个成员变量中,以便其余的回调方法使用。

OnCreateActionView()

        这是你给菜单项定义操做视窗的地方。使用从构造器中接收的Context对象,获取一个LayoutInflater对象的实例,而且用XML资源来填充操做视窗,而后注册事件监听器。如:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. public View onCreateActionView() {  

  2.     // Inflate the action view to be shown on the action bar.  

  3.     LayoutInflater layoutInflater = LayoutInflater.from(mContext);  

  4.     View view = layoutInflater.inflate(R.layout.action_provider, null);  

  5.     ImageButton button = (ImageButton) view.findViewById(R.id.button);  

  6.     button.setOnClickListener(new View.OnClickListener() {  

  7.         @Override  

  8.         public void onClick(View v) {  

  9.             // Do something...  

  10.         }  

  11.     });  

  12.     return view;  

  13. }  


onPerformDefaultAction()
         
在选中悬浮菜单中的菜单时,系统会调用这个方法,而且操做提供器应该这对这个选中的菜单项执行默认的操做。

       可是,若是你的操做提供器提供了一个子菜单,即便是悬浮菜单中一个菜单项的子菜单,那么也要经过onPrepareSubMenu()回调方法来显示子菜单。这样onPerformDefaultAction()在子菜单显示时就不会被调用。

       注意:实现了onOptionsItemSelected()回调方法的Activity或Frament对象可以经过处理item-selected事件(而且返回true)来覆盖操做提供器的默认行为,这种状况下,系统不会调用onPerformDefaultAction()回调方法。

添加导航选项标签

       当你想要在一个Activity中提供导航选择标签时,使用操做栏的选项标签是一个很是好的选择(而不是使用TabWidget类),由于系统会调整操做栏选项标签来适应不一样尺寸的屏幕的须要---在屏幕足够宽的时候,导航选项标签会被放到主操做栏中;当屏幕太窄的时候,选项标签会被放到一个分离的横条中,如图9和图10所示。

      

          图9. Honeycomb Gallery应用程序中的操做栏选项标签的截图

      

          图10. 在窄屏设备上被堆放在操做栏中的选项标签的截屏 

       要使用选项标签在Fragmengt之间切换,你必须在每次选择一个选项标签时执行一个Fragment事务。若是你不熟悉如何使用FragmentTransaction对象来改变Fragment,请阅读Fragment开发指南。

       首先,你的布局必须包含一个用于放置跟每一个Fragment对象关联的选项标签的ViewGroup对象。而且要确保这个ViewGroup对象有一个资源ID,以便你可以在选项标签的切换代码中可以引用它。另外,若是选项标签的内容填充在Activity的布局中(不包括操做栏),那么Activity不须要任何布局(你甚至不须要调用setContentView()方法)。相反,你可以把每一个Fragment对象放到默认的根ViewGroup对象中,你可以用android.R.id.content ID来引用这个ViewGroup对象(在Fragment执行事务期间,你可以在下面的示例代码中看到如何使用这个ID的。

        决定了Fragment对象在布局中的显示位置后,添加选项标签的基本过程以下:

          1.  实现ActionBar.TabListener接口。这个接口中回调方法会响应选项标签上的用户事件,以便你可以切换Fragment对象;

           2.  对于每一个要添加的选项标签,都要实例化一个ActionBar.Tab对象,而且调用setTabListener()方法设置ActionBar.Tab对象的事件监听器。还能够用setText()或setIcon()方法来设置选项标签的标题或图标。

         3.  经过调用addTab()方法,把每一个选项标签添加到操做栏。

        在查看ActionBar.TabListener接口时,注意到回调方法只提供了被选择的ActionBar.Tab对象和执行Fragment对象事务的FragmentTransaction对象---没有说明任何有关Fragment切换的事。所以。你必须定义本身的每一个ActionBar.Tab之间的关联,以及ActionBar.Tab所表明的适合的Fragment对象(为了执行合适的Fragment事务)。依赖你的设计,会有几种不一样的方法来定义这种关联。在下面的例子中,ActionBar.TabListener接口的实现提供了一个构造器,这样每一个新的选项标签都会使用它本身的监听器实例。每一个监听器实例都定义了几个在对应Fragment对象上执行事务时必须的几个成员变量。

       例如,如下示例是ActionBar.TabListener接口的一种实现,在这个实现中,每一个选项标签都使用了它本身的监听器实例:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. public static class TabListener<T extends Fragment> implements ActionBar.TabListener {  

  2.     private Fragment mFragment;  

  3.     private final Activity mActivity;  

  4.     private final String mTag;  

  5.     private final Class<T> mClass;  

  6.   

  7.     /** Constructor used each time a new tab is created. 

  8.       * @param activity  The host Activity, used to instantiate the fragment 

  9.       * @param tag  The identifier tag for the fragment 

  10.       * @param clz  The fragment's Class, used to instantiate the fragment 

  11.       */  

  12.     public TabListener(Activity activity, String tag, Class<T> clz) {  

  13.         mActivity = activity;  

  14.         mTag = tag;  

  15.         mClass = clz;  

  16.     }  

  17.   

  18.     /* The following are each of the ActionBar.TabListener callbacks */  

  19.   

  20.     public void onTabSelected(Tab tab, FragmentTransaction ft) {  

  21.         // Check if the fragment is already initialized  

  22.         if (mFragment == null) {  

  23.             // If not, instantiate and add it to the activity  

  24.             mFragment = Fragment.instantiate(mActivity, mClass.getName());  

  25.             ft.add(android.R.id.content, mFragment, mTag);  

  26.         } else {  

  27.             // If it exists, simply attach it in order to show it  

  28.             ft.attach(mFragment);  

  29.         }  

  30.     }  

  31.   

  32.     public void onTabUnselected(Tab tab, FragmentTransaction ft) {  

  33.         if (mFragment != null) {  

  34.             // Detach the fragment, because another one is being attached  

  35.             ft.detach(mFragment);  

  36.         }  

  37.     }  

  38.   

  39.     public void onTabReselected(Tab tab, FragmentTransaction ft) {  

  40.         // User selected the already selected tab. Usually do nothing.  

  41.     }  

  42. }  


       警告:针对每一个回调中的Fragment事务,你都没必要调用commit()方法---系统会调用这个方法,而且若是你本身调用了这个方法,有可能会抛出一个异常。你也不能把这些Fragment事务添加到回退堆栈中。

在这个例子中,当对应的选项标签被选择时,监听器只是简单的把一个Fragment对象附加(attach()方法)到Activity布局上---或者,若是没有实例化,就会建立这个Fragment对象,而且把它添加(add()方法)到布局中(android.R.id.content ViewGroup的一个子类),当这个选项标签解除选择时,对应的Fragment对象也会被解除与布局的依附关系。

       ActionBar.TabListener的实现作了大量的工做,剩下的事情就是建立每一个ActionBar.Tab对象并把它添加到ActionBar对象中,另外,你必须调用setNavigationMode(NAVIGATION_MODE_TABS)方法来让选项标签可见。若是选项标签的标题实际指示了当前的View对象,你也能够经过调用setDisplayShowTitleEnabled(false)方法来禁用Activity的标题。

       例如,下面的代码使用上面定义的监听器在操做栏中添加了两个选项标签。

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. @Override  

  2. protected void onCreate(Bundle savedInstanceState) {  

  3.     super.onCreate(savedInstanceState);  

  4.     // Notice that setContentView() is not used, because we use the root  

  5.     // android.R.id.content as the container for each fragment  

  6.   

  7.     // setup action bar for tabs  

  8.     ActionBar actionBar = getActionBar();  

  9.     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);  

  10.     actionBar.setDisplayShowTitleEnabled(false);  

  11.   

  12.     Tab tab = actionBar.newTab()  

  13.             .setText(R.string.artist)  

  14.             .setTabListener(new TabListener<ArtistFragment>(  

  15.                     this"artist", ArtistFragment.class));  

  16.     actionBar.addTab(tab);  

  17.   

  18.     tab = actionBar.newTab()  

  19.         .setText(R.string.album)  

  20.         .setTabListener(new TabListener<AlbumFragment>(  

  21.                 this"album", AlbumFragment.class));  

  22.     actionBar.addTab(tab);  

  23. }  


        注意:以上有关ActionBar.TabListener的实现,只是几种可能的技术之一。在API Demos应用中你可以看到更多的这种样式。

        若是Activity终止了,那么你应该保存当前选择的选项标签的状态,以便当用户再次返回时,你可以打开合适的选项标签。在保存状态的时刻,你可以用getSelectedNavigationIndex()方法查询当前的被选择的选项标签。这个方法返回被选择的选项标签的索引位置。

       警告:保存每一个Fragment所必须的状态是相当重要的,由于当用户用选项标签在Fragment对象间切换时,它会查看Fragment在离开时样子。

       注意:在某些状况下,Android系统会把操做栏选项标签做为一个下拉列表来显示,以便确保操做栏的最优化显示。

添加下拉式导航

       做为Activity内部的另外一种导航(或过滤)模式,操做栏提供了内置的下拉列表。下拉列表可以提供Activity中内容的不一样排序模式。

       启用下拉式导航的基本过程以下:

         1.  建立一个给下拉提供可选项目的列表,以及描画列表项目时所使用的布局;

         2.  实现ActionBar.OnNavigationListener回调,在这个回调中定义当用户选择列表中一个项目时所发生的行为;

         3.  用setNavigationMode()方法该操做栏启用导航模式,如:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. ActionBar actionBar = getActionBar();  

  2. actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);  

        4.  用setListNavigationCallbacks()方法给下拉列表设置回调方法,如:

[java] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);  

这个方法须要SpinnerAdapter和ActionBar.OnNavigationListener对象。下面是 SpinnerAdapter and ActionBar.OnNavigationListener 的例子。

 Example SpinnerAdapter and OnNavigationListener

设置操做栏的样式

       若是你对应用程序中的可视构件进行了定制化的设计,那么你可能也会要对操做栏作一些从新设计,以便跟应用程序的设计匹配。要这样作的话,须要使用Android的样式与主题框架中的一些特殊的样式属性来从新设置操做栏的样式。

       注意:改变外观的背景图片依赖与当前按钮的状态(选择、按下、解除选择),所以你使用的可描画的资源必须是一个可描画的状态列表。

       警告:对于你提供的全部可描画的背景,要确保使用NinePatch类型可描画资源,以便容许图片的拉伸。NinePatch类型的图片应该比40像素高30像素宽的图片要小。


普通的外观

android:windowActionBarOverlay

      这个属性声明了操做栏是否应该覆盖Activity布局,而不是相对Activity的布局位置的偏移。这个属性的默认值是false。

      一般,在屏幕上,操做栏须要它本身的空间,而且把剩下的空间用来填充Activity的布局。当操做栏四覆盖模式时,Activity会使用全部的有效空间,系统会在Activity的上面描画操做栏。若是你想要在操做栏隐藏和显示时,布局中的内容保持固定的尺寸好位置,那么这种覆盖模式是有用的。你也可能只是为了显示效果来使用它,由于你能够给操做栏设置半透明的背景,以便用户依然可以看到操做栏背后的Activity布局。

       注意:默认状况下,Holo主题会用半透明背景来描画操做栏。可是,你可以用本身的样式来修改它,而且默认的状况下,DeviceDefault主题在不一样的设备上可能使用不透明的背景。

       覆盖模式被启用时,Activity布局不会感知到操做栏覆盖在它的上面,所以,在操做栏覆盖的区域,最好不要放置一些重要的信息或UI组件。若是适合,你可以引用平台的actionBarSize值来决定操做栏的高度,例如,在XML布局文件中引用这个值。

[html] view plain copy

 print?在CODE上查看代码片派生到个人代码片

  1. <SomeView  

  2.     ...  

  3.     android:layout_marginTop="?android:attr/actionBarSize" />  


       你还可以用getHeight()方法在运行时获取操做栏的高度。若是在Activity生存周期的早期调用这个方法,那么在调用时所反映的操做栏的高度可能不包括被堆放的操做栏(由于导航选项标签)。要看如何在运行时判断操做栏总的高度(包括被堆放的操做栏),请看Honeycomb Gallery示例应用中的TitlesFragment类。

操做项元素

  • android:actionButtonStyle

  • 给操做项按钮定义样式资源。

  • android:actionBarItemBackground

  •  给每一个操做项的背景定义可描画资源(被添加在API 级别 14中)。

  • android:itemBackground

  •  给每一个悬浮菜单项的背景定义可描画资源。

  • android:actionBarDivider

  • 给操做项之间的分隔线定义可描画资源(被添加在API 级别 14中)

  • android:actionMenuTextColor

  • 给显示在操做项中文本定义颜色。

  • android:actionMenuTextAppearance

  •  给显示在操做项中文本定义样式资源。

  • android:actionBarWidgetTheme

  • 给做为操做视窗被填充到操做栏中的可视构件定义主题资源(被添加在API级别14中)。

  • 导航选项标签

  • android:actionBarTabStyle

  •  给操做栏中的选项标签订义样式资源。

  • android:actionBarTabBarStyle

  • 给显示在导航选项标签下方的细条定义样式资源。

  • android:actionBarTabTextStyle

  • 给导航选项标签中的文本定义样式资源。

  • 下拉列表

  • android:actionDropDownStyle

  •  给下拉导航列表定义样式(如背景和文本样式)。

  • 如,下例XML文件中给操做栏定义了一些定制的样式:

    [html] view plain copy

  •  

  • print ? 在CODE上查看代码片 派生到个人代码片
    1. <?xml version="1.0" encoding="utf-8"?>  

    2. <resources>  

    3.     <!-- the theme applied to the application or activity -->  

    4.     <style name="CustomActivityTheme" parent="@android:style/Theme.Holo">  

    5.         <item name="android:actionBarTabTextStyle">@style/CustomTabTextStyle</item>  

    6.         <item name="android:actionBarDivider">@drawable/ab_divider</item>  

    7.         <item name="android:actionBarItemBackground">@drawable/ab_item_background</item>  

    8.     </style>  

    9.   

    10.     <!-- style for the action bar tab text -->  

    11.     <style name="CustomTabTextStyle" parent="@android:style/TextAppearance.Holo">  

    12.         <item name="android:textColor">#2456c2</item>  

    13.     </style>  

    14. </resources>  


           注意:必定要在<style>标签中声明一个父主题,这样定制的主题能够继承全部没有明确声明的样式。在修改操做栏样式时,使用父主题是相当重要的,它会让你可以简单的覆写你想要改变的操做栏样式,而不影响你不想修改的样式(如文本的外观或操做项的边缘)。

          你可以在清单文件中把定制的主题应用到整个应用程序或一个单独的Activity对象,如:

    [html] view plain copy

  •  

  • print ? 在CODE上查看代码片 派生到个人代码片
    1. <application android:theme="@style/CustomActivityTheme" ... />  


    高级样式

          若是须要比上述属性更高级的样式,能够在Activity的主题中包含android:actionBarStyle和android:actionBarSplitStyle属性。这两个属性的每个都指定了另外一种可以给操做栏定义各类属性的样式,包括带有android:background、android:backgroundSplit、android:backgroundStacked属性的不一样背景。若是要覆盖这些操做栏样式,就要确保定义一个像Widget.Holo.ActionBar这样的父操做栏样式。

    例如,若是要改变操做栏背景,你可使用下列样式:

    [html] view plain copy

  •  

  • print ? 在CODE上查看代码片 派生到个人代码片
    1. <?xml version="1.0" encoding="utf-8"?>  

    2. <resources>  

    3.     <!-- the theme applied to the application or activity -->  

    4.     <style name="CustomActivityTheme" parent="@android:style/Theme.Holo">  

    5.         <item name="android:actionBarStyle">@style/MyActionBar</item>  

    6.         <!-- other activity and action bar styles here -->  

    7.     </style>  

    8.   

    9.     <!-- style for the action bar backgrounds -->  

    10.     <style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">  

    11.         <item name="android:background">@drawable/ab_background</item>  

    12.         <item name="android:backgroundStacked">@drawable/ab_background</item>  

    13.         <item name="android:backgroundSplit">@drawable/ab_split_background</item>  

    14.     </style>  

    15. </resources>

相关文章
相关标签/搜索