控件|控件 -- ActionBar

一、概念 在Android 3.0中,ActionBar是一个非常重要的交互元素,ActionBar取代了传统的标题栏,在程序运行中一直置于顶部,对于Android平板设备来说,屏幕更大,标题栏使用ActionBar来设计可以展示更多丰富的内容,方便操控。
二、使用 1.添加ActionBar
在Android 3.0及更高的版本中,Activity中都默认包含有ActionBar。
2.取消ActionBar
manifest设置:


代码设置:
ActionBar actionBar = getActionBar(); actionBar.hide(); //隐藏actionBar.show(); //显示

【控件|控件 -- ActionBar】如果使用一个主题(theme)来移除Activity上的ActionBar,那么窗口将不再会有ActionBar,因此在运行时也就没有办法来添加ActionBar,调用getActionBar()方法会返回null值。
3.添加Action按钮
ActionBar可以根据应用程序当前的功能来提供与其相关的Action按钮,这些按钮都会以图标或文字的形式直接显示在ActionBar上。当然,如果按钮过多,ActionBar上显示不完,多出的一些按钮可以隐藏在overflow里面(最右边的三个点就是overflow按钮),点击一下overflow按钮就可以看到全部的Action按钮了。
(1)定义menu资源
//menu_main.xml

这里我们通过标签定义了三个Action按钮。
标签中又有一些属性,其中:
id:是该Action按钮的唯一标识符;
icon:用于指定该按钮的图标;
title:用于指定该按钮可能显示的文字(在图标能显示的情况下,通常不会显示文字);
actionViewClass:用于指定一个构建视窗所使用的布局资源;
showAsAction:用于指定按钮显示的位置。
showAsAction主要有以下几种值可选:
ifRoom:会显示在Item中,但是如果已经有4个或者4个以上的Item时会隐藏在溢出列表中,当然个数并不仅仅局限于4个,依据屏幕的宽窄而定。
never:永远不会显示,只会在溢出列表中显示,而且只显示标题,所以在定义item的时候,最好把标题都带上。
always:无论是否溢出,总会显示。
withText:示意ActionBar要显示文本标题,ActionBar会尽可能显示这个标题,但是如果图标有效并且受到ActionBar空间的限制,文本标题有可能显示不全。
collapseActionView:声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开,否则这个操作视窗在默认的情况下是可见的,并且即便在用于不适用的时候,也要占据操作栏的有效空间,一般要配合ifRoom一起使用才会有效果。
title中的内容通常情况下只会在overflow中显示出来,ActionBar中由于屏幕空间有限,默认是不会显示title内容的。但是出于以下几种因素考虑,即使title中的内容无法显示出来,我们也应该给每个item中都指定一个title属性:
●当ActionBar中的剩余空间不足的时候,如果Action按钮指定的showAsAction属性是ifRoom的话,该Action按钮就会出现在overflow当中,此时就只有title能够显示了。
●如果Action按钮在ActionBar中显示,用户可能通过长按该Action按钮的方式来查看到title的内容。
(2)重写Activity的onCreateOptionsMenu()方法
当Activity启动的时候,系统会调用Activity的onCreateOptionsMenu()方法来取出所有的Action按钮,我们只需要在这个方法中去加载一个menu资源,并把所有的Action按钮都定义在资源文件里面就可以了。
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_main, menu); return super.onCreateOptionsMenu(menu); }

(3)重写Activity的onOptionsItemSelected()方法
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.user_p: Toast.makeText(this, "你点击了“用户”按键!", Toast.LENGTH_SHORT).show(); return true; case R.id.write_p: Toast.makeText(this, "你点击了“发布”按键!", Toast.LENGTH_SHORT).show(); return true; case R.id.favo_p: Toast.makeText(this, "你点击了“收藏”按键!", Toast.LENGTH_SHORT).show(); return true; default: return super.onOptionsItemSelected(item); } }

4.通过ActionBar图标进行导航
ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); return true; ... } }

5.添加ActionView
ActionView是一种可以在ActionBar中替换Action按钮的控件,它可以允许用户在不切换界面的情况下通过ActionBar完成一些较为丰富的操作。比如说,你需要完成一个搜索功能,就可以将SeachView这个控件添加到ActionBar中。
(1)定义menu资源
为了声明一个ActionView,我们可以在menu资源中通过actionViewClass属性来指定一个控件:

(2)重写Activity的onCreateOptionsMenu()方法
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); MenuItem searchItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) searchItem.getActionView(); // 配置SearchView的属性 ... return super.onCreateOptionsMenu(menu); }

有些程序可能还希望在ActionView展开和合并的时候显示不同的界面,其实我们只需要去注册一个ActionView的监听器就能实现这样的功能:
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); MenuItem searchItem = menu.findItem(R.id.action_search); searchItem.setOnActionExpandListener(new OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { Log.d("TAG", "on expand"); return true; }@Override public boolean onMenuItemActionCollapse(MenuItem item) { Log.d("TAG", "on collapse"); return true; } }); return super.onCreateOptionsMenu(menu); }

6.添加ActionProvider
和ActionView有点类似,ActionProvider也可以将一个Action按钮替换成一个自定义的布局。但不同的是,ActionProvider能够完全控制事件的所有行为,并且还可以在点击的时候显示子菜单。
(1)定义menu资源
为了添加一个ActionProvider,我们需要在标签中指定一个actionViewClass属性,在里面填入ActionProvider的完整类名。我们可以通过继承ActionProvider类的方式来创建一个自己的ActionProvider,同时Android也提供好了几个内置的ActionProvider,比如说ShareActionProvider。
...

(2)重写Activity的onCreateOptionsMenu()方法
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_main, menu); MenuItem shareItem = menu.findItem(R.id.action_share); ShareActionProvider provider = (ShareActionProvider) shareItem .getActionProvider(); provider.setShareIntent(getDefaultIntent()); return super.onCreateOptionsMenu(menu); }private Intent getDefaultIntent() { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/*"); return intent; }

这里我们通过getDefaultIntent()方法来构建了一个Intent,该Intent会将所有可以共享图片的程序都列出来。
这个ShareActionProvider点击之后是可以展开的,有点类似于overflow的效果,这就是ActionProvider的子菜单。
7.添加导航Tabs
Tabs的应用可以算是非常广泛了,它可以使得用户非常轻松地在应用程序中切换不同的视图。而Android官方更加推荐使用ActionBar中提供的Tabs功能,因为它更加的智能,可以自动适配各种屏幕的大小。比如说,在平板上屏幕的空间非常充足,Tabs会和Action按钮在同一行显示,而如果是在手机上,屏幕的空间不够大的话,Tabs和Action按钮则会分为两行显示。
添加步骤:
(1)实现ActionBar.TabListener接口,这个接口提供了Tab事件的各种回调,比如当用户点击了一个Tab时,可以进行切换Tab的操作;
(2)为每一个想添加的Tab创建一个ActionBar.Tab的实例,并且调用setTabListener()方法来设置ActionBar.TabListener。除此之外,还需要调用setText()方法来给当前Tab设置标题;
(3)最后调用ActionBar的addTab()方法将创建好的Tab添加到ActionBar中。
//TabListener import android.app.ActionBar; import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; public class TabListener implements ActionBar.TabListener { private Fragment mFragment; private final Activity mActivity; private final String mTag; private final Class mClass; /** Constructor used each time a new tab is created. * @param activityThe host Activity, used to instantiate the fragment * @param tagThe identifier tag for the fragment * @param clzThe fragment's Class, used to instantiate the fragment */ public TabListener(Activity activity, String tag, Class clz) { mActivity = activity; mTag = tag; mClass = clz; }/* The following are each of the ActionBar.TabListener callbacks */public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { // Check if the fragment is already initialized if (mFragment == null) { // If not, instantiate and add it to the activity mFragment = Fragment.instantiate(mActivity, mClass.getName()); ft.add(android.R.id.content, mFragment, mTag); } else { // If it exists, simply attach it in order to show it ft.attach(mFragment); } }public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { if (mFragment != null) { // Detach the fragment, because another one is being attached ft.detach(mFragment); } }public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { // User selected the already selected tab. Usually do nothing. } }//Fragment1,Fragment2、Fragment3类似 import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class Fragment1 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment1, container, false); } }//fragment1.xml,fragment2.xml、fragment3.xml类似 //MainActivity private void initView() { // 提示getActionBar方法一定在setContentView后面 ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // 添加Tab选项 ActionBar.Tab tab = actionBar .newTab() .setText("澳门风云2") .setTabListener( new TabListener(this, "film1", Fragment1.class)); actionBar.addTab(tab); tab = actionBar .newTab() .setText("五十度灰") .setTabListener( new TabListener(this, "film2", Fragment2.class)); actionBar.addTab(tab); tab = actionBar .newTab() .setText("爸爸去哪儿2") .setTabListener( new TabListener(this, "film3", Fragment3.class)); actionBar.addTab(tab); }

8.添加下拉列表导航
作为Activity内部的另一种导航(或过滤)模式,操作栏提供了内置的下拉列表。下拉列表能够提供Activity中内容的不同排序模式。
添加步骤:
(1)创建一个给下拉提供可选项目的列表,以及描画列表项目时所使用的布局;
(2)实现ActionBar.OnNavigationListener回调,在这个回调中定义当用户选择列表中一个项目时所发生的行为;
(3)用setNavigationMode()方法该操作栏启用导航模式;
(4)用setListNavigationCallbacks()方法给下拉列表设置回调方法。
//strings.xmlFragment1 Fragment2 Fragment3//MainActivity private ActionBar.OnNavigationListener mOnNavigationListener; private String[] arry_list; private void initView() { ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); // //导航模式必须设为NAVIGATION_MODE_LIST actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); // 定义一个下拉列表数据适配器 SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list, android.R.layout.simple_spinner_dropdown_item); arry_list = getResources().getStringArray(R.array.action_list); mOnNavigationListener = new ActionBar.OnNavigationListener() {@Override public boolean onNavigationItemSelected(int position, long itemId) { Fragment newFragment = null; switch (position) { case 0: newFragment = new Fragment1(); break; case 1: newFragment = new Fragment2(); break; case 2: newFragment = new Fragment3(); break; default: break; } getFragmentManager() .beginTransaction() .replace(R.id.container, newFragment, arry_list[position]).commit(); return true; } }; actionBar.setListNavigationCallbacks(mSpinnerAdapter, mOnNavigationListener); }

9.自定义ActionBar样式
(1)使用主题
可以将主题应用到整个应用程序,也可以只应用于某个Activity。通过在AndroidManifest.xml文件中给或标签指定android:theme属性就可以实现了。如果只想让ActionBar使用深色系的主题,而Activity的内容部分仍然使用浅色系的主题,可以通过声明以下主题来实现:
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"

(2)自定义背景
如果想要修改ActionBar的背景,我们可以通过创建一个自定义主题并重写actionBarStyle属性来实现。这个属性可以指向另外一个样式,然后我们在这个样式中重写background这个属性就可以指定一个drawable资源或颜色,从而实现自定义背景的功能。
@style/MyActionBar#f4842d //修改ActionBar的背景色 #d27026 //修改Tabs的背景色

(3)自定义文字颜色
@style/MyActionBar @style/MyActionBarTabText... @style/MyActionBarTitleText#fff //修改ActionBar的标题文字颜色#fff //修改Tabs的标题文字颜色

(4)自定义Tab Indicator
为了可以明确分辨出我们当前选中的是哪一个Tab项,通常情况下都会在选中Tab的下面加上一条横线作为标识,这被称作Tab Indicator。如果要自定义Tab Indicator,首先我们需要重写actionBarTabStyle这个属性,将它指向一个新建的Tab样式,然后重写background这个属性即可。需要注意的是,background必须要指定一个state-list drawable文件,这样在各种不同状态下才能显示出不同的效果。
步骤1:准备四张图片,分别用于表示Tab的四种状态:选中未按下、选中且按下、未选中未按下、未选中且按下,并创建state-list drawable文件。
//actionbar_tab_indicator.xml

步骤2:修改style.xml文件。
...... @style/MyActionBarTabs @drawable/actionbar_tab_indicator

    推荐阅读