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

图一:


图二:


下载完成后,在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属性,
  1. <activity android:theme="@style/Theme.AppCompat.Light">  
(3.0以上的工程中,activity默认设置了 Theme.Holo 这个属性

  1.  ActionBar bar = getSupportActionBar();//2.1以上的工程用这个方法获取对actionbar的引用,并且向上兼容  
  2. //   ActionBar bar = getActionBar();//3.0以上的工程,可以用这个方法获取  
  3.   
  4. bar.hide();//你可以通过这两个方法,来控制actionBar的显示状态  
  5. bar.show();  
至此,我们已经完成了android 2.1平台对actionbar的完美兼容,可以在2.1的环境下,开发使用各种actionbar的API,下面,我们就讲解几个主要的用法。(有些手机可能还是无法完美使用actionbar,在下面的讲解中,注意事项3 会解释这一原因)

一 .在actionbar 上面,直接添加子元素。

在Activity生成的时候,系统会调用onCreateOptionsMenu这个方法,如果要是想在ActionBar上面添加视图子元素的话,需要重写这个方法,如下面的代码所示:
  1. @Override  
  2. public boolean onCreateOptionsMenu(Menu menu) {  
  3.  // Inflate the menu; this adds items to the action bar if it is present.  
  4.     MenuInflater inflater = getMenuInflater();  
  5.     inflater.inflate(R.menu.main, menu);  
  6.     return super.onCreateOptionsMenu(menu);  
  7. }  
在项目工程的res文件夹下的menu下,新建一个设置menu的xml.比如像我这样的 main.xml
  1. <menu xmlns:android="http://schemas.android.com/apk/res/android" >  
  2.     <item android:id="@+id/action_search"  
  3.           android:icon="@drawable/ic_launcher_info_active_holo"  
  4.           android:title="Search"  
  5.           android:orderInCategory="1"  
  6.           android:showAsAction="ifRoom"/>  
  7.     <item android:id="@+id/action_compose"  
  8.           android:icon="@drawable/ic_launcher_trashcan_active_holo"  
  9.           android:title="compose"  
  10.           android:orderInCategory="1"  
  11.           android:showAsAction="ifRoom"/>  
  12. </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文件如下面代码所示。
  1. <menu xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:yourapp="http://schemas.android.com/apk/res-auto" >  
  3.     <item android:id="@+id/action_search"  
  4.           android:icon="@drawable/ic_launcher_info_active_holo"  
  5.           android:title="Search"  
  6.           android:orderInCategory="1"  
  7.           yourapp:showAsAction="ifRoom"/>  
  8.     <item android:id="@+id/action_compose"  
  9.           android:icon="@drawable/ic_launcher_trashcan_active_holo"  
  10.           android:title="compose"  
  11.           android:orderInCategory="1"  
  12.           yourapp:showAsAction="ifRoom"/>  
  13. </menu>  
这样,你在V7包的环境下,用带有menu键的手机跑一边程序,你就会在actionbar上面看到自定义的item了。
另外,在带有menu键的手机张,如果你使用的是V7包,那么当actionbar 的item 过多时,多出的item也不会被收集在action overflow中,你只有按menu键的时候,他们才会显示出来。

关于如何响应这些item的点击事件,那就更容易了,你只需在activity中,重写下面的方法,根据item的id号来进行判别响应就可以了。
  1. @Override  
  2. public boolean onOptionsItemSelected(MenuItem item) {  
  3.  switch(item.getItemId()){  
  4.  case R.id.action_search:  
  5.   Log.i("TAG""=========第一个被点中了");  
  6.   break;  
  7.  case R.id.action_compose:  
  8.   Log.i("TAG""=========第二个被点中了");  
  9.   break;  
  10.  }  
  11.  return true;  
  12. }  
二 。在界面的左上角,显示一个后退的箭头,并且可以响应点击事件

如果想在界面的左上角,显示如图的返回箭头,并且可以响应它的点击事件。其实,很简单,只需要一段代码即可。
  1. ActionBar bar = getSupportActionBar();  
  2. bar .setDisplayHomeAsUpEnabled(true);  
这样就可以显示出来了,如果想响应它的点击事件,也是重写下面的这个方法,然后判断id号为 android.R.id.home 的item
  1. @Override  
  2. public boolean onOptionsItemSelected(MenuItem item) {  
  3.  switch(item.getItemId()){  
  4.  case R.id.action_search:  
  5.   Log.i("TAG""=========第一个被点中了");  
  6.   break;  
  7.  case R.id.action_compose:  
  8.   Log.i("TAG""=========第二个被点中了");  
  9.   break;  
  10.  case android.R.id.home:  
  11.   Log.i("TAG""=========选中返回键");  
  12.   break;  
  13.  }  
  14.  return true;  
  15. }  
ActionBar有一种   split action bar 的概念。指的是,在一些屏幕比较窄的情况下,将actionbar的item,尽可能多的展示在屏幕的下方,类似于下图中红色边框标注的部分

为了能够展示出这种效果,同时兼顾2.1环境下的版本,你需要对activity进行如下设置
  1. <activity  
  2.     android:name="com.example.actionbartest.MainActivity"  
  3.     android:label="@string/app_name"  
  4.     android:theme="@style/Theme.AppCompat.Light"  
  5.     android:uiOptions="splitActionBarWhenNarrow" >  
  6.     <intent-filter>  
  7.         <action android:name="android.intent.action.MAIN" />  
  8.         <category android:name="android.intent.category.LAUNCHER" />  
  9.     </intent-filter>  
  10.     <meta-data  
  11.         android:name="android.support.UI_OPTIONS"  
  12.         android:value="splitActionBarWhenNarrow" />  
  13. </activity>  
给activity加入 uiOptions的属性,设置为 splitActionBarWhenNarrow,同时设置一个meta选项
这样,就可以实现上图的效果了。

四。 Adding Navigation Tabs
添加导航tab栏,是一种很常见的设计样式,相比大家也经常用到它,2.x时代,一般大家都是用tabhost来实现,自从谷歌推出设计规范后,谷歌大力提倡使用    Navigation Tabs 加上 Fragment 以及 viewpager 来实现导航页面的滑屏切换和点击切换,如图所示,即为 Navigation Tabs

下面我就给大家贴一下示例代码,注释中写的很详细。
  1. public class NavigationActivity extends ActionBarActivity {  
  2.  ViewPager mViewPager;  
  3.  TabsAdapter mTabsAdapter;  
  4.  @Override  
  5.  protected void onCreate(Bundle savedInstanceState) {  
  6.   // TODO Auto-generated method stub  
  7.   super.onCreate(savedInstanceState);  
  8.     
  9.   //构造一个ViewPager,使其成为这个Activity的视图容器  
  10.   mViewPager = new ViewPager(this);  
  11.   mViewPager.setId(11);  
  12.   setContentView(mViewPager);  
  13.   
  14.   //获取对Actionbar的引用,这种方式兼容android2.1  
  15.   final ActionBar bar = getSupportActionBar();  
  16.   //设置Actionbar的模式为 引导Tab的模式,这样,actionbar才会显示出 Tab标签  
  17.   bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);  
  18.   bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);  
  19.     
  20.   //如果你只想显示Navigation Tabs,不想显示actionbar上面的标题等布局,你可以调用下面两行代码来实现  
  21. //   bar.setDisplayShowHomeEnabled(false);  
  22. //   bar.setDisplayShowTitleEnabled(false);  
  23.   
  24.   //构造一个自定义的Adapter,使将Fragment作为一个页面,放入到viewpager中,并且使viewpager和actionbar相关联起来。  
  25.   mTabsAdapter = new TabsAdapter(this, mViewPager);  
  26.   mTabsAdapter.addTab(bar.newTab().setText("Simple"),  
  27.     TestFragment.classnull);  
  28.   mTabsAdapter.addTab(bar.newTab().setText("List"),  
  29.     TestFragment.classnull);  
  30.   mTabsAdapter.addTab(bar.newTab().setText("Cursor"),  
  31.     TestFragment.classnull);  
  32.  }  
  33.   
  34.    
  35.  /** 
  36.   * 自定义一个adapter,FragmentPagerAdapter是一个用来连接ViewPager和Fragment的适配器。 
  37.   * 实现ActionBar.TabListener接口 是为了响应Navigation Tabs的点击事件 
  38.   * 实现ViewPager.OnPageChangeListener 是为了响应ViewPager的滑屏事件 
  39.   */  
  40.  public static class TabsAdapter extends FragmentPagerAdapter implements  
  41.    ActionBar.TabListener, ViewPager.OnPageChangeListener {  
  42.   private final Context mContext;  
  43.   private final ActionBar mActionBar;  
  44.   private final ViewPager mViewPager;  
  45.   private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();  
  46.   
  47.   static final class TabInfo {  
  48.    private final Class<?> clss;  
  49.    private final Bundle args;  
  50.   
  51.    TabInfo(Class<?> _class, Bundle _args) {  
  52.     clss = _class;  
  53.     args = _args;  
  54.    }  
  55.   }  
  56.   
  57.   public TabsAdapter(ActionBarActivity activity, ViewPager pager) {  
  58.    super(activity.getSupportFragmentManager());  
  59.    mContext = activity;  
  60.    mActionBar = activity.getSupportActionBar();  
  61.    mViewPager = pager;  
  62.    mViewPager.setAdapter(this);  
  63.    mViewPager.setOnPageChangeListener(this);  
  64.   }  
  65.   
  66.   public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {  
  67.    TabInfo info = new TabInfo(clss, args);  
  68.    tab.setTag(info);  
  69.    tab.setTabListener(this);  
  70.    mTabs.add(info);  
  71.    //将Tab 添加到 Actionbar当中去,这样才会显示出来  
  72.    mActionBar.addTab(tab);  
  73.    notifyDataSetChanged();  
  74.   }  
  75.   
  76.   @Override  
  77.   public int getCount() {  
  78.    return mTabs.size();  
  79.   }  
  80.   
  81.   @Override  
  82.   public Fragment getItem(int position) {  
  83.    //为每一个ViewPager的页面 实例化一个Fragment的实体  
  84.    TabInfo info = mTabs.get(position);  
  85.    return Fragment.instantiate(mContext, info.clss.getName(),  
  86.      info.args);  
  87.   }  
  88.   
  89.   @Override  
  90.   public void onPageScrolled(int position, float positionOffset,  
  91.     int positionOffsetPixels) {  
  92.   }  
  93.   
  94.   @Override  
  95.   public void onPageSelected(int position) {  
  96.    //当viewpager滑动时,actionbar的tab标签也要相应的改变,一一对应  
  97.    mActionBar.setSelectedNavigationItem(position);  
  98.   }  
  99.   
  100.   @Override  
  101.   public void onPageScrollStateChanged(int state) {  
  102.   }  
  103.   
  104.   @Override  
  105.   public void onTabSelected(Tab tab, FragmentTransaction ft) {  
  106.    //当点击选择不同的tab时,viewpager的页面也要相应的改变,使其一一对应  
  107.    Object tag = tab.getTag();  
  108.    for (int i = 0; i < mTabs.size(); i++) {  
  109.     if (mTabs.get(i) == tag) {  
  110.      mViewPager.setCurrentItem(i);  
  111.     }  
  112.    }  
  113.   }  
  114.   
  115.   @Override  
  116.   public void onTabUnselected(Tab tab, FragmentTransaction ft) {  
  117.   }  
  118.   
  119.   @Override  
  120.   public void onTabReselected(Tab tab, FragmentTransaction ft) {  
  121.   }  
  122.  }  
  123. }  

(以上的这些代码,我会整理成一个demo程序,上传到csdn上,大家如果有需要,可以去下载,下载地址: http://download.csdn.net/detail/pringlee2011/6827427

至此,我就把如何在Android2.X的环境下兼容ActionBar,以及ActionBar的常用方法介绍完了。我以上的代码,也全部兼容了android2.1以上的版本环境。不知道我描述的是否清楚,大家可以亲自敲一遍代码,把这些例子跑一边,如果有什么新的发现或者我描述有误的地方,希望大家能多多探讨。只要大家掌握了这些用法,那么以后在开发的过程中,涉及到Actionbar的基本用法,我想应该能应对自如了。回头我会再写两篇关于ActionBar的博客,那里面会介绍一些关于actionbar的更进一步的用法,希望能够对大家有所帮助。

这篇博客是 Android弹无虚发 系列的第一篇,以后的日子里,我会陆续更新这一系列的博客,将我平时的工作经验以及学习所得分享给大家,希望能够帮助到大家,也希望大家能够喜欢,多多支持我的博客。 新人还望共勉,大神敬请拍砖!!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值