您的位置:首页 > 移动开发 > Android开发

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

2014-01-09 00:10 501 查看
自从谷歌发布 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属性,
<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,尽可能多的展示在屏幕的下方,类似于下图中红色边框标注的部分



为了能够展示出这种效果,同时兼顾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弹无虚发 系列的第一篇,以后的日子里,我会陆续更新这一系列的博客,将我平时的工作经验以及学习所得分享给大家,希望能够帮助到大家,也希望大家能够喜欢,多多支持我的博客。 新人还望共勉,大神敬请拍砖!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息