这部分代码很简单,仅仅是调用了MenuInflater的inflate()方法来加载menu资源就能够了。如今从新运行一下程序,结果以下图所示:html
能够看到,action_compose和action_delete这两个按钮已经在ActionBar中显示出来了,而action_settings这个按钮因为showAsAction属性设置成了never,因此被隐藏到了overflow当中,只要点击一下overflow按钮就能够看到它了。java
这里咱们注意到,显示在ActionBar上的按钮都只有一个图标而已,咱们在title中指定的文字并无显示出来。没错,title中的内容一般状况下只会在overflow中显示出来,ActionBar中因为屏幕空间有限,默认是不会显示title内容的。可是出于如下几种因素考虑,即便title中的内容没法显示出来,咱们也应该给每一个item中都指定一个title属性:android
当用户点击Action按钮的时候,系统会调用Activity的onOptionsItemSelected()方法,经过方法传入的MenuItem参数,咱们能够调用它的getItemId()方法和menu资源中的id进行比较,从而辨别出用户点击的是哪个Action按钮,好比:[java] view plaincopyide
能够看到,咱们让每一个Action按钮被点击的时候都弹出一个Toast,如今从新运行一下代码,结果以下图所示:ui
启用ActionBar图标导航的功能,能够容许用户根据当前应用的位置来在不一样界面之间切换。好比,A界面展现了一个列表,点击某一项以后进入了B界面,这时B界面就应该启用ActionBar图标导航功能,这样就能够回到A界面。this
咱们能够经过调用setDisplayHomeAsUpEnabled()方法来启用ActionBar图标导航功能,好比:[java] view plaincopyspa
如今从新运行一下程序,结果以下图所示:.net
能够看到,在ActionBar图标的左侧出现了一个向左的箭头,一般状况下这都表示返回的意思,所以最简单的实现就是在它的点击事件里面加入finish()方法就能够了,以下所示:[java] view plaincopy设计
当点击ActionBar图标的时候,系统一样会调用onOptionsItemSelected()方法,而且此时的itemId是android.R.id.home,因此finish()方法也就是加在这里的了。3d
如今看上去,ActionBar导航和Back键的功能貌似是同样的。没错,若是咱们只是简单地finish了一下,ActionBar导航和Back键的功能是彻底同样的,但ActionBar导航的设计初衷并非这样的,它和Back键的功能仍是有一些区别的,举个例子吧。
上图中的Conversation List是收件箱的主界面,如今咱们点击第一封邮件会进入到Conversation1 details界面,而后点击下一封邮件会进入到Conversation 2 details界面,再点击下一封邮箱会进入到Conversation3 details界面。好的,这个时候若是咱们按下Back键,应该会回到Conversation 2 details界面,再按一次Back键应该回到Conversation1 details界面,再按一次Back键才会回到Conversation List。而ActionBar导航则不该该表现出这种行为,不管咱们当前在哪个Conversation details界面,点击一下导航按钮都应该回到Conversation List界面才对。
这就是ActionBar导航和Back键在设计上的区别,那么该怎样才能实现这样的功能呢?其实并不复杂,实现标准的ActionBar导航功能只需三步走。
第一步咱们已经实现了,就是调用setDisplayHomeAsUpEnabled()方法,并传入true。
第二步须要在AndroidManifest.xml中配置父Activity,以下所示:[html] view plaincopy
能够看到,这里经过meta-data标签指定了MainActivity的父Activity是LaunchActivity,在Android 4.1版本以后,也能够直接使用android:parentActivityName这个属性来进行指定,以下所示:[html] view plaincopy
第三步则须要对android.R.id.home这个事件进行一些特殊处理,以下所示:[java] view plaincopy
其中,调用NavUtils.getParentActivityIntent()方法能够获取到跳转至父Activity的Intent,而后若是父Activity和当前Activity是在同一个Task中的,则直接调用navigateUpTo()方法进行跳转,若是不是在同一个Task中的,则须要借助TaskStackBuilder来建立一个新的Task。
这样,就按照标准的规范成功实现ActionBar导航的功能了。
ActionView是一种能够在ActionBar中替换Action按钮的控件,它能够容许用户在不切换界面的状况下经过ActionBar完成一些较为丰富的操做。好比说,你须要完成一个搜索功能,就能够将SeachView这个控件添加到ActionBar中。
为了声明一个ActionView,咱们能够在menu资源中经过actionViewClass属性来指定一个控件,例如可使用以下方式添加SearchView:[html] view plaincopy
注意在showAsAction属性中咱们还声明了一个collapseActionView,这个值表示该控件能够被合并成一个Action按钮。
如今从新运行一下程序,效果以下图所示:
OK,果真有一个搜索样式的Action按钮出现了,如今点击一下这个搜索按钮,效果以下图所示:
能够看到,这时SearchView就会展开占满整个ActionBar,而其它的Action按钮因为将showAsAction属性设置成了ifRoom,此时都会隐藏到overflow当中。
若是你还但愿在代码中对SearchView的属性进行配置(好比添加监听事件等),彻底没有问题,只须要在onCreateOptionsMenu()方法中获取该ActionView的实例就能够了,代码以下所示:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
// Configure the search info and add any event listeners
if (searchView != null) {
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
Toast.makeText(MainActivity.this, query, Toast.LENGTH_SHORT).show();
searchItem.collapseActionView();
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
}
return true;
}
在获得了SearchView的实例以后,就能够任意地配置它的各类属性了。关于SearchView的更多详细用法,能够参考官方文档 http://developer.android.com/guide/topics/search/search-dialog.html 。
除此以外,有些程序可能还但愿在ActionView展开和合并的时候显示不一样的界面,其实咱们只须要去注册一个ActionView的监听器就能实现这样的功能了,代码以下所示:[java] view plaincopy
能够看到,调用MenuItem的setOnActionExpandListener()方法就能够注册一个监听器了,当SearchView展开的时候就会回调onMenuItemActionExpand()方法,当SearchView合并的时候就会调用onMenuItemActionCollapse()方法,咱们在这两个方法中进行相应的UI操做就能够了。
虽然如今咱们已经掌握了很多ActionBar的用法,可是当你真正去使用它的时候仍是可能会遇到各类各样的问题,好比不少人都会碰到overflow按钮不显示的状况。明明是一样的一份代码,overflow按钮在有些手机上会显示,而在有些手机上恰恰就不显示,这是为何呢?后来我总结了一下,overflow按钮的显示状况和手机的硬件状况是有关系的,若是手机没有物理Menu键的话,overflow按钮就能够显示,若是有物理Menu键的话,overflow按钮就不会显示出来。好比咱们启动一个有Menu键的模拟器,而后将代码运行到该模拟器上,结果以下图所示:
能够看到,ActionBar最右边的overflow按钮不见了!那么此时咱们如何查看隐藏在overflow中的Action按钮呢?其实很是简单,按一下Menu键,隐藏的内容就会从底部出来了,以下图所示:
看到这里相信很多朋友都想吐槽一下了,这显然是一种很是蛋疼的设计,在不一样手机上居然显示了不一样的界面,并且操做方法也彻底不同,这样会给用户一种很是不习惯的感受。话说Google为何要把ActionBar的overflow设计成这样我也不太理解,可是咱们仍是有办法改变这一默认行为的。
实际上,在ViewConfiguration这个类中有一个叫作sHasPermanentMenuKey的静态变量,系统就是根据这个变量的值来判断手机有没有物理Menu键的。固然这是一个内部变量,咱们没法直接访问它,可是能够经过反射的方式修改它的值,让它永远为false就能够了,代码以下所示:[java] view plaincopy
这里咱们在onCreate()方法的最后调用了setOverflowShowingAlways()方法,而这个方法的内部就是使用反射的方式将sHasPermanentMenuKey的值设置成false,如今从新运行一下代码,结果以下图所示:
能够看到,即便是在有Menu键的手机上,也能让overflow按钮显示出来了,这样就能够大大增长咱们软件界面和操做的统一性。
若是你点击一下overflow按钮去查看隐藏的Action按钮,你会发现这部分Action按钮都是只显示文字不显示图标的,以下图所示:
这是官方的默认效果,Google认为隐藏在overflow中的Action按钮都应该只显示文字。固然,若是你认为这样不够美观,但愿在overflow中的Action按钮也能够显示图标,咱们仍然能够想办法来改变这一默认行为。
其实,overflow中的Action按钮应不该该显示图标,是由MenuBuilder这个类的setOptionalIconsVisible方法来决定的,若是咱们在overflow被展开的时候给这个方法传入true,那么里面的每个Action按钮对应的图标就都会显示出来了。调用的方法固然仍然是用反射了,代码以下所示:[java] view plaincopy
能够看到,这里咱们重写了一个onMenuOpened()方法,当overflow被展开的时候就会回调这个方法,接着在这个方法的内部经过返回反射的方法将MenuBuilder的setOptionalIconsVisible变量设置为true就能够了。
如今从新运行一下代码,结果以下图所示:
使用split action bar
即将除Up Button、图标和标题以外的全部item移到底栏上
<manifest ...>
<activity uiOptions="splitActionBarWhenNarrow" ... >
<meta-data
android:name="android.support.UI_OPTIONS"
android:value="splitActionBarWhenNarrow" />
</activity>
</manifest>
好了,目前为止咱们已经把ActionBar的基础知识介绍完了,那么今天的讲解就到这里,下篇文章中我会带领你们一块儿更深刻地了解ActionBar,感兴趣的朋友请继续阅读 Android ActionBar彻底解析(下)。