一. 什么是ActionBar,优点和缺点?
Action Bar是一种新増的导航栏功能,在Android 3.0之后加入到系统的API当中,它标识了用户当前操作界面的位置,并提供了额外的用户动作、界面导航等功能。使用ActionBar的好处是,它可以给提供一种全局统一的UI界面,使得用户在使用任何一款软件时都懂得该如何操作,并且ActionBar还可以自动适应各种不同大小的屏幕。目前在实际开发中,很多项目都会用到ActionBar,本篇文章参考http://blog.csdn.net/guolin_blog/article/details/18234477并增加了自己的内容,Thank you !
二. 如何使用ActionBar
1. 添加ActionBar
在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或其子类
2. 删除ActionBar
第一种方法:将theme指定成Theme.Holo.NoActionBar
第二种方法:调用以下代码去设置
ActionBar actionBar = getActionBar();
actionBar.hide();
3. 图标修改
在清单文件中指定Activity的login属性:android:logo="@drawable/ xxx "4. 标题修改
在清单文件中指定Activity的label属性:android:label="xxx"
5. 添加Action按钮
当Activity启动的时候,系统会调用Activity的onCreateOptionsMenu()方法来取出所有的Action按钮
①.布局文件添加:在res/menu/xxx.xml中设置
<item
android:id="@+id/action_compose"
android:icon="@drawable/ic_action_compose"
android:showAsAction="always"
android:title="@string/action_compose"/>
②重写onCreateOptionsMenu方法
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
注意:当ActionBar中的剩余空间不足的时候,如果Action按钮指定的showAsAction属性是ifRoom的话,该Action按钮就会出现在overflow当中,此时就只有title能够显示了。如果Action按钮在ActionBar中显示,用户可能通过长按该Action按钮的方式来查看到title的内容。
6. 处理点击事件
重写onOptionsItemSelected方法 调用item.getItemId() 去处理
三. 如何使用ActionBar实现导航
ActionBar导航和Back键的区别:ActionBar中捕捉Home键调用finish方法,效果类似于Back键,但违背了最初的设计
三步设置ActionBar导航:
①. 调用setDisplayHomeAsUpEnabled(true),显示Home按钮
②. 在清单文件中配置父Activity
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.actionbartest.LaunchActivity" />
注:android4.1之后可以直接通过parentActivityName属性来指定
③. 捕捉Home按钮的点击事件进行处理
case android.R.id.home:
Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
TaskStackBuilder.create(this)
.addNextIntentWithParentStack(upIntent)
.startActivities();
} else {
upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, upIntent);
}
return true;
四. 添加Action View
ActionView是一种可以在ActionBar中替换Action按钮的控件,它可以允许用户在不切换界面的情况下通过ActionBar完成一些较为丰富的操作,为了声明一个ActionView,我们可以在menu资源中通过actionViewClass属性来指定一个控件,例如可以使用如下方式添加SearchView:
<item
android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:actionViewClass="android.widget.SearchView"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/action_search" />
如果你还希望在代码中对SearchView的属性进行配置(比如添加监听事件等),完全没有问题,只需要在onCreateOptionsMenu()方法中获取该ActionView的实例就可以了,代码如下所示:
@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);
}
可以看到,调用MenuItem的setOnActionExpandListener()方法就可以注册一个监听器了,当SearchView展开的时候就会回调onMenuItemActionExpand()方法,当SearchView合并的时候就会调用onMenuItemActionCollapse()方法,我们在这两个方法中进行相应的UI操作就可以了。
五. Overflow按钮不显示
overflow按钮的显示情况和手机的硬件情况是有关系的,如果手机没有物理Menu键的话,overflow按钮就可以显示,如果有物理Menu键的话,overflow按钮就不会显示出来,在ViewConfiguration这个类中有一个叫做sHasPermanentMenuKey的静态变量,系统就是根据这个变量的值来判断手机有没有物理Menu键的。当然这是一个内部变量,我们无法直接访问它,但是可以通过反射的方式修改它的值,让它永远为false就可以了,代码如下所示:@Override
protected void onCreate(Bundle savedInstanceState) {
......
setOverflowShowingAlways();
}
private void setOverflowShowingAlways() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e) {
e.printStackTrace();
}
}
六. 让Overflow显示图标
Google认为隐藏在overflow中的Action按钮都应该只显示文字,如果想显示图标,可以用反射的方法改变MenuBuilder这个类的setOptionalIconsVisible变量的值@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
try {
Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
} catch (Exception e) {
}
}
}
return super.onMenuOpened(featureId, menu);
}
七. 改变Overflow的图标
<item
android:id="@+id/action_search"
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/actionbar_search_icon"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/action_search"/>
<item
android:id="@+id/overflow_menus"
android:actionProviderClass="@android:style/Widget.Holo.ActionButton.Overflow"
android:orderInCategory="100"
android:showAsAction="always"
android:title="@string/action_search">
<menu>
<item
android:id="@+id/action_plus"
android:actionProviderClass="com.example.wechatsample.PlusActionProvider"
android:icon="@drawable/actionbar_add_icon"
android:showAsAction="ifRoom"
android:title="@string/action_plus"/>
<item
android:id="@+id/action_album"
android:icon="@drawable/ofm_photo_icon"
android:title="@string/action_album"/>
<item
android:id="@+id/action_collection"
android:icon="@drawable/ofm_collect_icon"
android:title="@string/action_collection"/>
<item
android:id="@+id/action_card"
android:icon="@drawable/ofm_card_icon"
android:title="@string/action_card"/>
<item
android:id="@+id/action_settings"
android:icon="@drawable/ofm_setting_icon"
android:title="@string/action_settings"/>
<item
android:id="@+id/action_feed"
android:icon="@drawable/ofm_feedback_icon"
android:title="@string/action_feed"/>
</menu>
</item>
将要在Overflow内部显示的item用一个menu包裹起来,在onCreateOptionsMenu方法中调用menu.getItem(1).setIcon(R.drawable.actionbar_add_icon);
七. 自定义ActionBar
ActionBar actionBar = ((ActionBarActivity) getActivity()).getSupportActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
View titleView = View.inflate(mContext, R.layout.title_mapmain, null);
titleView.setBackgroundColor(Color.WHITE);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
actionBar.setCustomView(titleView,params)
八. 添加Action Provider
和Action View有点类似,Action Provider也可以将一个Action按钮替换成一个自定义的布局。但不同的是,Action Provider能够完全控制事件的所有行为,并且还可以在点击的时候显示子菜单。
如何在一个Menu的Item中添加子菜单呢?
①.定义类继承ActionProvider,在menu.xml的item中通过actionProviderClass属性来引用所定义的类。
②.重写onPrepareSubMenu方法调用SubMenu的clear , add , setIcon ,setOnMenuItemClickListener方法来完成对子菜单的操作
③.重写hasSubMenu方法返回true
具体案例请参考文章最后提供的Demo。
九. 添加导航Tabs
Android官方更加推荐使用ActionBar中提供的Tabs功能,因为它更加的智能,可以自动适配各种屏幕的大小如何使用ActionBar提供的Tab功能?
①. 实现ActionBar.TabListener接口,这个接口提供了Tab事件的各种回调,比如当用户点击了一个Tab时,你就可以进行切换Tab的操作。②. 为每一个你想添加的Tab创建一个ActionBar.Tab的实例,并且调用setTabListener()方法来设置ActionBar.TabListener。除此之外,还需要调用setText()方法来给当前Tab设置标题。③. 最后调用ActionBar的addTab()方法将创建好的Tab添加到ActionBar中。
十. 自定义ActionBar样式
1. 使用主题
Theme.Holo,这是一个深色系的主题。Theme.Holo.Light,这是一个浅色系的主题。
2. 自定义背景
如果想要修改ActionBar的背景,我们可以通过创建一个自定义主题并重写actionBarStyle属性来实现。这个属性可以指向另外一个样式,然后我们在这个样式中重写background这个属性就可以指定一个drawable资源或颜色,从而实现自定义背景的功能。在style.xml中添加
<resources>
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">@style/MyActionBar</item>
</style>
<style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar">
<item name="android:background">#f4842d</item> 重写了background属性,并给它指定了一个背景色
<item name="android:backgroundStacked">#d27026</item> 重写了backgroundStacked属性,这个属性就是用于指定Tabs背景色的
</style>
</resources>
然后在AndroidManifest.xml的Activity标签中声明android:theme="@style/CustomActionBarTheme"
3. 自定义文字颜色
修改ActionBar标题颜色为白色
<style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar">
<item name="android:titleTextStyle">@style/MyActionBarTitleText</item>
</style>
<style name="MyActionBarTitleText" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title">
<item name="android:textColor">#fff</item>
</style>
修改tab字体颜色
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">@style/MyActionBar</item>
<item name="android:actionBarTabTextStyle">@style/MyActionBarTabText</item>
</style>
<style name="MyActionBarTabText"
parent="@android:style/Widget.Holo.ActionBar.TabText">
<item name="android:textColor">#fff</item>
</style>
4. 自定义Tab Indicator
为了可以明确分辨出我们当前选中的是哪一个Tab项,通常情况下都会在选中Tab的下面加上一条横线作为标识,这被称作Tab Indicator
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false"
android:state_pressed="false"
android:drawable="@drawable/tab_unselected" />
<item android:state_selected="true"
android:state_pressed="false"
android:drawable="@drawable/tab_selected" />
<item android:state_selected="false"
android:state_pressed="true"
android:drawable="@drawable/tab_unselected_pressed" />
<item android:state_selected="true"
android:state_pressed="true"
android:drawable="@drawable/tab_selected_pressed" />
</selector>
这里先是重写了actionBarTabStyle这个属性,并将它指向了另一个自定义样式MyActionBarTabs,接着在这个样式中重写background属性,然后指向我们刚才创建的actionbar_tab_indicator即可。
<resources>
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
......
<item name="android:actionBarTabStyle">@style/MyActionBarTabs</item>
</style>
<style name="MyActionBarTabs" parent="@android:style/Widget.Holo.ActionBar.TabView">
<item name="android:background">@drawable/actionbar_tab_indicator</item>
</style>
</resources>
最后在Actionbar使用的过程中还需要知道下面几个小知识点:
setHomeButtonEnabled:这个小于4.0版本的默认值为true的。但是在4.0及其以上是false,该方法的作用:决定左上角的图标是否可以点击
// 给左上角图标的左边加上一个返回的图标 。对应ActionBar.DISPLAY_HOME_AS_UP
actionBar.setDisplayHomeAsUpEnabled(true)
//使左上角图标是否显示,如果设成false,则没有程序图标,仅仅就个标题,否则,显示应用程序图标,对应id为android.R.id.home,对应ActionBar.DISPLAY_SHOW_HOME
actionBar.setDisplayShowHomeEnabled(true)
//使自定义的普通View能在title栏显示,即actionBar.setCustomView能起作用,对应ActionBar.DISPLAY_SHOW_CUSTOM
actionBar.setDisplayShowCustomEnabled(true)
//对应ActionBar.DISPLAY_SHOW_TITLE。
actionBar.setDisplayShowTitleEnabled(true)
其中setHomeButtonEnabled和setDisplayShowHomeEnabled共同起作用,如果setHomeButtonEnabled设成false,即使setDisplayShowHomeEnabled设成true,图标也不能点击
下面给出3个Demo,让你彻底玩转ActionBar的使用。