Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略

自从谷歌发布 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包如何下载?如何引用呢?别急,我给大家贴几张图,大家就明白了。

图一:


图二:
Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略_第1张图片

下载完成后,在SDK所在的目录下,寻找这个路径 \extras\android\support\v7  就可以看到刚刚下载完成的V7支持包了。
V7下一共有三个工程,我们只需要用到appcompat这个工程就可以了。
接下来我们将其作为一个Library导入到工程中。请看图解:

图三:
Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略_第2张图片

图四:
Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略_第3张图片

有时候,这个Library引入后,eclipse会报资源缺失的错误,如果遇到了这样的情况,我们还需要多做两步其它的操作。如图:
图五:



然后在Build to path这个选项中,Add to build path。将这两个jar包Add之后,右击整个library工程,选择build path,然后选择 configure  Build path, 然后见下图操作:

图六:
Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略_第4张图片

这样操作完成后,应该就不会有资源缺失的错误了。

将v7这个Library导入后,我们就开始新建一个新的Android工程,这个步骤就不用贴图详解了,大家都快点吐了吧。
建好之后,需要引入这个v7 Library,步骤如下图:

图七:
Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略_第5张图片

图八:
Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略_第6张图片

至此,我们对V7 Library的引用过程就完成了,下面,我们就可以在我们2.1的工程环境下,开发使用ActionBar了。


新建一个Activity,使其继承 ActionBarActivity,在AndroidManifest.xml中,为这个activity设置一个theme属性,
<activity android:theme="@style/Theme.AppCompat.Light">
(3.0以上的工程中,activity默认设置了 Theme.Holo 这个属性

 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);
 }
在项目工程的res文件夹下的menu下,新建一个设置menu的xml.比如像我这样的 main.xml
<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键的时候,他们才会显示出来。

关于如何响应这些item的点击事件,那就更容易了,你只需在activity中,重写下面的方法,根据item的id号来进行判别响应就可以了。
 @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;
 }
ActionBar有一种   split action bar 的概念。指的是,在一些屏幕比较窄的情况下,将actionbar的item,尽可能多的展示在屏幕的下方,类似于下图中红色边框标注的部分
Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略_第7张图片
为了能够展示出这种效果,同时兼顾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弹无虚发 系列的第一篇,以后的日子里,我会陆续更新这一系列的博客,将我平时的工作经验以及学习所得分享给大家,希望能够帮助到大家,也希望大家能够喜欢,多多支持我的博客。 新人还望共勉,大神敬请拍砖!!!


你可能感兴趣的:(android,Actionbar,tabs,design,Navigation,兼容android2.1)