自从谷歌发布 Android Design 设计规范后,越来越多的产品加入了ActionBar的设计,可以预见的是,这种界面模式,会越来越成为一种简约风格的标配。当初ActionBar这个API是在android 3.0之后加入的,这使得很多android手机的开发者只能在Android4.0 SDK之后,才能使用ActionBar进行开发。后来大神辈出,搞出了很多可以兼容2.X平台的Library,比较出名的有AcitonBarSherlock,GitHub上面的https://github.com/johannilsson/android-actionbar,这些实现的效果都挺不错的,以前我也会使用这些类库。但是今天,我却不打算去介绍这些类库的使用方法,因为现在谷歌已经推出了API可以去兼容2.X平台了! 什么? Android 2.X的SDK也可以使用actionbar了?没错!!!今天就告诉大家怎么用。
首先你需要用eclipse去下载一个
Support Library
它是谷歌发布的一个支持包,其中
android.support.v7 这个包中就含有对ActionBar的支持,可以在android2.1的环境下开发设计actionbar。看到这个包名,想必大家不会太陌生吧,因为android开发的朋友,肯定会经常跟V4和V13这两个包打交道,他们都是android的支持包。后面的问题是,这个v7包如何下载?如何引用呢?别急,我给大家贴几张图,大家就明白了。
图一:
图二:
下载完成后,在SDK所在的目录下,寻找这个路径 \extras\android\support\v7 就可以看到刚刚下载完成的V7支持包了。
V7下一共有三个工程,我们只需要用到appcompat这个工程就可以了。
接下来我们将其作为一个Library导入到工程中。请看图解:
图三:
图四:
有时候,这个Library引入后,eclipse会报资源缺失的错误,如果遇到了这样的情况,我们还需要多做两步其它的操作。如图:
图五:
然后在Build to path这个选项中,Add to build path。将这两个jar包Add之后,右击整个library工程,选择build path,然后选择 configure Build path, 然后见下图操作:
图六:
这样操作完成后,应该就不会有资源缺失的错误了。
将v7这个Library导入后,我们就开始新建一个新的Android工程,这个步骤就不用贴图详解了,大家都快点吐了吧。
建好之后,需要引入这个v7 Library,步骤如下图:
图七:
图八:
至此,我们对V7 Library的引用过程就完成了,下面,我们就可以在我们2.1的工程环境下,开发使用ActionBar了。
新建一个Activity,使其继承 ActionBarActivity,在AndroidManifest.xml中,为这个activity设置一个theme属性,
- ActionBar bar = getSupportActionBar();//2.1以上的工程用这个方法获取对actionbar的引用,并且向上兼容
- // ActionBar bar = getActionBar();//3.0以上的工程,可以用这个方法获取
- bar.hide();//你可以通过这两个方法,来控制actionBar的显示状态
- bar.show();
至此,我们已经完成了android 2.1平台对actionbar的完美兼容,可以在2.1的环境下,开发使用各种actionbar的API,下面,我们就讲解几个主要的用法。(有些手机可能还是无法完美使用actionbar,在下面的讲解中,注意事项3 会解释这一原因)
一 .在actionbar 上面,直接添加子元素。
在Activity生成的时候,系统会调用onCreateOptionsMenu这个方法,如果要是想在ActionBar上面添加视图子元素的话,需要重写这个方法,如下面的代码所示:
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
- return super.onCreateOptionsMenu(menu);
- }
- <menu xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:id="@+id/action_search"
- android:icon="@drawable/ic_launcher_info_active_holo"
- android:title="Search"
- android:orderInCategory="1"
- android:showAsAction="ifRoom"/>
- <item android:id="@+id/action_compose"
- android:icon="@drawable/ic_launcher_trashcan_active_holo"
- android:title="compose"
- android:orderInCategory="1"
- android:showAsAction="ifRoom"/>
- </menu>
这样,当你重新运行这个项目的时候,你就可以在actionbar上面看到你自己定义的这两个item了。不过看似很简单的设置,却有几个注意事项需要特别的跟大家说明一下。
1.
android:showAsAction 这个属性表明的是,actionbar上面,item的显示状态,ifRoom的含义指的的是,只要actionbar上面还有足够的空间可以用来展示,那么这些item就会直接显示出来。如果空间不足的话,系统会将一些优先级比较低的item,隐藏到actionbar最右边的action overflow里面,下图中红色标注的区域就是action overflow
2. 有些同学会问,那item的优先级是怎么设定的呢? 请注意上面menu的xml文件中,有
android:orderInCategory 这个属性,这个属性设置的值越高,它的优先级就越低,如果actionbar的空间不足的话,它就会把
orderInCategory 值比较高的给隐藏到右侧的overflow里面去,如果你不去主动设置
android:orderInCategory,那么系统就会默认,越靠后的item,它的优先级就越低。
3. 第三点,也是最重要的一点。如果大家用V7这个library跑一边这个例子的话,你也许会发现,无论你怎么设置item的属性,它始终不会在actionbar上面显示。这是为什么呢? 原来,如果你是用V7这个支持库来实现的actionbar,而且你的手机是带有menu键的老手机,那么它的framework层是不支持
android:showAsAction这个属性的。你需要为刚才menu的xml文件,署名一个命名空间,所以更改后的xml文件如下面代码所示。
- <menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
- <item android:id="@+id/action_search"
- android:icon="@drawable/ic_launcher_info_active_holo"
- android:title="Search"
- android:orderInCategory="1"
- yourapp:showAsAction="ifRoom"/>
- <item android:id="@+id/action_compose"
- android:icon="@drawable/ic_launcher_trashcan_active_holo"
- android:title="compose"
- android:orderInCategory="1"
- yourapp:showAsAction="ifRoom"/>
- </menu>
这样,你在V7包的环境下,用带有menu键的手机跑一边程序,你就会在actionbar上面看到自定义的item了。
另外,在带有menu键的手机张,如果你使用的是V7包,那么当actionbar 的item 过多时,多出的item也不会被收集在action overflow中,你只有按menu键的时候,他们才会显示出来。
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch(item.getItemId()){
- case R.id.action_search:
- Log.i("TAG", "=========第一个被点中了");
- break;
- case R.id.action_compose:
- Log.i("TAG", "=========第二个被点中了");
- break;
- }
- return true;
- }
如果想在界面的左上角,显示如图的返回箭头,并且可以响应它的点击事件。其实,很简单,只需要一段代码即可。
- ActionBar bar = getSupportActionBar();
- bar .setDisplayHomeAsUpEnabled(true);
这样就可以显示出来了,如果想响应它的点击事件,也是重写下面的这个方法,然后判断id号为 android.R.id.home 的item
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch(item.getItemId()){
- case R.id.action_search:
- Log.i("TAG", "=========第一个被点中了");
- break;
- case R.id.action_compose:
- Log.i("TAG", "=========第二个被点中了");
- break;
- case android.R.id.home:
- Log.i("TAG", "=========选中返回键");
- break;
- }
- return true;
- }
为了能够展示出这种效果,同时兼顾2.1环境下的版本,你需要对activity进行如下设置
- <activity
- android:name="com.example.actionbartest.MainActivity"
- android:label="@string/app_name"
- android:theme="@style/Theme.AppCompat.Light"
- android:uiOptions="splitActionBarWhenNarrow" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- <meta-data
- android:name="android.support.UI_OPTIONS"
- android:value="splitActionBarWhenNarrow" />
- </activity>
给activity加入 uiOptions的属性,设置为
splitActionBarWhenNarrow,同时设置一个meta选项
这样,就可以实现上图的效果了。
四。
Adding Navigation Tabs
添加导航tab栏,是一种很常见的设计样式,相比大家也经常用到它,2.x时代,一般大家都是用tabhost来实现,自从谷歌推出设计规范后,谷歌大力提倡使用
Navigation Tabs 加上 Fragment 以及 viewpager 来实现导航页面的滑屏切换和点击切换,如图所示,即为
Navigation Tabs
下面我就给大家贴一下示例代码,注释中写的很详细。
- public class NavigationActivity extends ActionBarActivity {
- ViewPager mViewPager;
- TabsAdapter mTabsAdapter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- //构造一个ViewPager,使其成为这个Activity的视图容器
- mViewPager = new ViewPager(this);
- mViewPager.setId(11);
- setContentView(mViewPager);
- //获取对Actionbar的引用,这种方式兼容android2.1
- final ActionBar bar = getSupportActionBar();
- //设置Actionbar的模式为 引导Tab的模式,这样,actionbar才会显示出 Tab标签
- bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
- //如果你只想显示Navigation Tabs,不想显示actionbar上面的标题等布局,你可以调用下面两行代码来实现
- // bar.setDisplayShowHomeEnabled(false);
- // bar.setDisplayShowTitleEnabled(false);
- //构造一个自定义的Adapter,使将Fragment作为一个页面,放入到viewpager中,并且使viewpager和actionbar相关联起来。
- mTabsAdapter = new TabsAdapter(this, mViewPager);
- mTabsAdapter.addTab(bar.newTab().setText("Simple"),
- TestFragment.class, null);
- mTabsAdapter.addTab(bar.newTab().setText("List"),
- TestFragment.class, null);
- mTabsAdapter.addTab(bar.newTab().setText("Cursor"),
- TestFragment.class, null);
- }
- /**
- * 自定义一个adapter,FragmentPagerAdapter是一个用来连接ViewPager和Fragment的适配器。
- * 实现ActionBar.TabListener接口 是为了响应Navigation Tabs的点击事件
- * 实现ViewPager.OnPageChangeListener 是为了响应ViewPager的滑屏事件
- */
- public static class TabsAdapter extends FragmentPagerAdapter implements
- ActionBar.TabListener, ViewPager.OnPageChangeListener {
- private final Context mContext;
- private final ActionBar mActionBar;
- private final ViewPager mViewPager;
- private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
- static final class TabInfo {
- private final Class<?> clss;
- private final Bundle args;
- TabInfo(Class<?> _class, Bundle _args) {
- clss = _class;
- args = _args;
- }
- }
- public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
- super(activity.getSupportFragmentManager());
- mContext = activity;
- mActionBar = activity.getSupportActionBar();
- mViewPager = pager;
- mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
- }
- public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
- TabInfo info = new TabInfo(clss, args);
- tab.setTag(info);
- tab.setTabListener(this);
- mTabs.add(info);
- //将Tab 添加到 Actionbar当中去,这样才会显示出来
- mActionBar.addTab(tab);
- notifyDataSetChanged();
- }
- @Override
- public int getCount() {
- return mTabs.size();
- }
- @Override
- public Fragment getItem(int position) {
- //为每一个ViewPager的页面 实例化一个Fragment的实体
- TabInfo info = mTabs.get(position);
- return Fragment.instantiate(mContext, info.clss.getName(),
- info.args);
- }
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- }
- @Override
- public void onPageSelected(int position) {
- //当viewpager滑动时,actionbar的tab标签也要相应的改变,一一对应
- mActionBar.setSelectedNavigationItem(position);
- }
- @Override
- public void onPageScrollStateChanged(int state) {
- }
- @Override
- public void onTabSelected(Tab tab, FragmentTransaction ft) {
- //当点击选择不同的tab时,viewpager的页面也要相应的改变,使其一一对应
- Object tag = tab.getTag();
- for (int i = 0; i < mTabs.size(); i++) {
- if (mTabs.get(i) == tag) {
- mViewPager.setCurrentItem(i);
- }
- }
- }
- @Override
- public void onTabUnselected(Tab tab, FragmentTransaction ft) {
- }
- @Override
- public void onTabReselected(Tab tab, FragmentTransaction ft) {
- }
- }
- }
(以上的这些代码,我会整理成一个demo程序,上传到csdn上,大家如果有需要,可以去下载,下载地址:
http://download.csdn.net/detail/pringlee2011/6827427)
至此,我就把如何在Android2.X的环境下兼容ActionBar,以及ActionBar的常用方法介绍完了。我以上的代码,也全部兼容了android2.1以上的版本环境。不知道我描述的是否清楚,大家可以亲自敲一遍代码,把这些例子跑一边,如果有什么新的发现或者我描述有误的地方,希望大家能多多探讨。只要大家掌握了这些用法,那么以后在开发的过程中,涉及到Actionbar的基本用法,我想应该能应对自如了。回头我会再写两篇关于ActionBar的博客,那里面会介绍一些关于actionbar的更进一步的用法,希望能够对大家有所帮助。
这篇博客是 Android弹无虚发 系列的第一篇,以后的日子里,我会陆续更新这一系列的博客,将我平时的工作经验以及学习所得分享给大家,希望能够帮助到大家,也希望大家能够喜欢,多多支持我的博客。 新人还望共勉,大神敬请拍砖!!!