转载请注明出处:http://blog.csdn.net/yegongheng/article/details/38488849
从今天开始,我们进入Android UI控件的学习阶段。首先我们来了解一下在Android开发中几乎每一个APP都会用到的一个非常重要的控件--Action Bar。Action Bar是在Android3.0之后新增的功能导航栏控件,它标识了用户当前操作界面的位置,并提供了额外的用户动作和界面导航功能。使用Action Bar的好处是可以为用户提供统一的导航操作栏,且将一些比较为重要的操作放在导航栏中方便用户操作,还有就是Action Bar可以自适应各种不同大小的屏幕,有良好的屏幕分辨率适配功能。下面是一张Android官网提供的一张Action Bar组成元素的的实例图片,并有相关的说明,如图下:
图标说明: 1、Action Bar图标;2、两个action 选项;3、overflow按钮。
基本了解了Action Bar的概念以及组成方式后,下面我们来深入地学习如何创建自己的Action Bar。
由于Action Bar是Android 3.0 (API level 11)之后才引入Android API中的,所以Android3.0之前的API是没有提供Action Bar的原生类和方法。那Android SDK为了兼容不同低版本和高版本的开发,另外提供了一个第三方的jar类库--android-support-v7-appcompat.jar。它封装了Action Bar相关的类和方法,使用Android3.0以下版本的Android SDK的同学只要引入该jar包,且子类Activity继承ActionBarActivity类便可使用Action Bar了。
接下来就可以开始使用Action Bar来进行我们的开发工作了,首先要为我们的界面(Activity)引入Action Bar,第一步是在AndroidManifest.xml文件中的对应声明的Activity添加以下属性值(这里默认是基于Android4.4的API上开发的):
<!--ActionBar浅色背景 ,Android3.0版本以下使用@style/Theme.AppCompat.Light--> android:theme="@android:style/Theme.Holo.Light"添加完该属性后我们为对应的界面添加了一个浅色背景的Action Bar,对应显示的界面如图下:
若要将其换成稍微深一点的背景色,可以将属性值改成如下:
<!--ActionBar深色背景,Android3.0版本以下使用@style/Theme.AppCompat.Light.DarkActionBar--> android:theme="@android:style/Theme.Holo.Light.DarkActionBar"对应的显示的界面如图下:
如果想要对整个APP的Activity设置相同的Action Bar样式,可以在AndroidManifest.xml中的<application/>设置全局的主题,这样可以将Theme样式应用到每一个Activity上,设置方法如同上。
<!--设置ActionBar图标 --> android:logo="@drawable/sys_icon" <!--设置ActionBar的名称 --> android:label="@string/main_title"代码设置的方法是首先通过调用上下文的getActionBar()方法获取ActionBar实例对象,然后再调用ActionBar对象的setIcon()和setTitle()方法分别设置ActionBar的图标和Title,具体的代码如下:
/** * 获取ActionBar实例对象,若是Android3.0之前的版本,需 * 调用getSupportActionBar()方法获取ActionBar实例对象 */ ActionBar mActionBar = getActionBar(); //设置ActionBar的icon mActionBar.setIcon(R.drawable.sys_icon); //设置ActionBar的title mActionBar.setTitle(R.string.main_title);设置完成后,运行程序,界面视图效果如下:
ActionBar mActionBar = getActionBar(); //是否启用ActionBar图标的导航功能 mActionBar.setDisplayHomeAsUpEnabled(true);该方法主要作用是设置ActionBar图标是否具有导航点击事件功能,接下来重写Menu的事件响应方法onOptionsItemSelected(MenuItem item),然后执行如下操作:
@Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { //ActionBar Home键ID case android.R.id.home: //关闭当前界面 finish(); break; default: break; } return true; }在模拟器上运行实例程序,操作及效果图如下:
<activity android:name="com.androidleaf.actionbar.activity.ScreenSecondActivity" android:logo="@drawable/sys_icon" android:label="@string/main_title" > <!-- 设置点击ActionBar图标时跳转的父类Activity界面名称,Android4.1之前使用这个设置, Android4.1之后可以 直接使用android:parentActivityName属性设置 --> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.androidleaf.actionbar.activity.MainActivity" /> </activity>
public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { //ActionBar Home键ID case android.R.id.home: //获取跳转至父类Activity的Intent Intent mIntent = NavUtils.getParentActivityIntent(this); //判断父类Activity和本Activity是否同属于一个Task,true则直接根据Intent跳转,否则重新创建一个Task if (NavUtils.shouldUpRecreateTask(this, mIntent)) { TaskStackBuilder.create(this) .addNextIntentWithParentStack(mIntent) .startActivities(); } else { mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); NavUtils.navigateUpTo(this, mIntent); } break; default: break; } return true; }执行完三个步骤后,我们来运行一下实例程序,执行效果如图下:
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context="com.androidleaf.actionbar.activity.MainActivity" > <item android:id="@+id/action_delete" android:orderInCategory="20" android:title="@string/action_delete" android:icon="@drawable/msg_icon_clear_all" android:showAsAction="always"/> <item android:id="@+id/action_tip" android:orderInCategory="30" android:title="@string/action_tip" android:icon="@drawable/poi_icon_action_tip" android:showAsAction="always"/> <item android:id="@+id/action_settings" android:orderInCategory="40" android:title="@string/action_setting" android:icon="@drawable/user_icon_setting" android:showAsAction="ifRoom"/> <item android:id="@+id/action_send" android:orderInCategory="50" android:title="@string/action_send" android:icon="@drawable/title_icon_send" android:showAsAction="ifRoom"/> </menu>每一个item都对应一个Action Item,我们可以为每个Item设置icon、title或showAsAction等,我们先对<item/>中的属性作用做一些说明:
@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; }最后我们来实现Item的事件响应方法,具体代码如下:
@Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); Resources mResources = getResources(); switch (id) { case R.id.action_delete: showInformation(mResources.getString(R.string.action_delete)); break; case R.id.action_tip: showInformation(mResources.getString(R.string.action_tip)); break; case R.id.action_settings: showInformation(mResources.getString(R.string.action_setting)); break; case R.id.action_send: showInformation(mResources.getString(R.string.action_send)); break; default: break; } return true; }至此,我们便按以上三个步骤代码编写完毕, ok,那我们先来运行一下程序看一下Action Items的效果图,如图下:
@Override public boolean onMenuOpened(int featureId, Menu menu) { // TODO Auto-generated method stub if (featureId == Window.FEATURE_ACTION_BAR && menu != null) { //通过发射机制根据类名获取setOptionalIconsVisible(boolean visible)方法,并为其设置true if (menu.getClass().getSimpleName().equals("MenuBuilder")) { try { Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); method.setAccessible(true); method.invoke(menu, true); } catch (Exception e) { } } } return super.onMenuOpened(featureId, menu); }然后再运行程序,效果如图下:
public class ScreenSecondActivity extends BaseActivity { private SpinnerAdapter mSpinnerAdapter; private TextView mTextView; @SuppressLint("NewApi") @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_screen_second); //是否启用ActionBar图标的导航功能 mActionBar.setDisplayHomeAsUpEnabled(true); mActionBar.setTitle(""); //1、设置Action Bar的导航模式 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); //2、初始化适配器并绑定下拉导航列表数据 mSpinnerAdapter = ArrayAdapter.createFromResource(getApplicationContext(), R.array.navigation_list_array, android.R.layout.simple_spinner_dropdown_item); //4、为ActionBar设置Adapter并为其设置事件监听 mActionBar.setListNavigationCallbacks(mSpinnerAdapter, new MyOnNavigationListener()); mTextView = (TextView)findViewById(R.id.screen_second_textview); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.screen_second, menu); return true; } @Override public boolean onMenuOpened(int featureId, Menu menu) { // TODO Auto-generated method stub 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); } @SuppressLint("NewApi") @Override public boolean onOptionsItemSelected(MenuItem item) { return true; } //3、 创建Action Bar下拉导航事件监听类 private class MyOnNavigationListener implements OnNavigationListener{ @Override public boolean onNavigationItemSelected(int itemPosition, long itemId) { // TODO Auto-generated method stub switch (itemPosition) { case 0: mTextView.setText("全部"); break; case 1: mTextView.setText("热门信息"); break; case 2: mTextView.setText("朋友"); break; case 3: mTextView.setText("家人"); break; default: break; } return true; } } }至此,我们便实现了在ActionBar中添加下拉导航的功能。
<item android:id="@+id/action_search" android:title="@string/action_search" android:orderInCategory="20" android:actionViewClass="android.widget.SearchView" android:icon="@drawable/common_icon_search" android:showAsAction="ifRoom|collapseActionView" />接着执行第二、三步骤的操作,具体代码如下:
MenuItem searchMenuItem = menu.findItem(R.id.action_search); //2、调用getActionView()获取SearchView对象 SearchView mSearchView = (SearchView) searchMenuItem.getActionView(); //获取搜索的管理对象 SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); //当前的Activity为可搜索的Activity mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); //以默认的方式展开 mSearchView.setIconifiedByDefault(true); //3、执行相关搜索操作 //......在这里我们只是简单地在ActionBar上引入一个SearchView,想要详细了解如何使用SearchView执行搜索操作的读者,可以阅读《Android实现Search搜索框原理分析》这篇博客。
最后我们再介绍一种十分有用的功能--Action Provider。它类似于上面讲的下拉导航的功能,不同的是下拉导航列表只能显示文本,Action Provider它可以自定义Item的布局选项,且Android系统也提供了好几个内置的Action Provider,例如ShareActionProvider,它可以很方便地为用户提供分享应用信息的功能,还有MediaRouteActionProvider,它主要是将MediaRouteButton展示在ActionBar上,并允许用户去选择Media Route并控制当前所选择的Media Route。使用Android内置的Action Provider与添加Action View的方式差不多,这里不多介绍,感兴趣的读者可以自行实验。我们在这里来学习一下如何自定义Action Provider,来添加我们所需的功能选项。在此之前,我们来看一下自定义Action Provider在ActionBar上的效果图,如图下:
一般的,自定义Action Provider并将其添加到ActionBar分为以下三个步骤:
1.在res/menu/screen_first.xml文件中对应的<item/>设置android:actionProviderClass="com.androidleaf.actionbar.widget.MyActionProvider";
2.创建继承Action Provider的子类,并重写onCreateActionView()、hasSubMenu()和onPrepareSubMenu()方法,在onPrepareSubMenu()方法中为Action Provider添加子菜单项,并为每个子菜单项设置事件监听;
3.在ScreenFirstActivity中重写onCreateOptionsMenu(Menu menu)并在该方法中根据ID获取MenuItem实例,并调用getActionProvider()方法获取MyActionProvider对象,并为子菜单项实现事件监听;
首先实现步骤一,res/menu/screen_first.xml文件中对应的<item/>代码如下:
<item android:id="@+id/action_write" android:title="@string/action_write" android:orderInCategory="30" android:actionProviderClass="com.androidleaf.actionbar.widget.MyActionProvider" android:icon="@drawable/icon_title_write" android:showAsAction="always" />
再来看一下继承ActionProvider的子类MyActionProvider的代码,如下:
public class MyActionProvider extends ActionProvider { private Context mContext; /** * 为Action Provider子菜单项的事件点击定义回调接口 */ private SubMenuItemClickListener mSubMenuItemClickListener; public interface SubMenuItemClickListener{ public void onSubMenuItem(int itemId); } public void setOnSubMenuItemClickListener(SubMenuItemClickListener mSubMenuItemClickListener){ this.mSubMenuItemClickListener = mSubMenuItemClickListener; } MyProviderOnMenuItemClickListener mProviderOnMenuItemClickListener = new MyProviderOnMenuItemClickListener(); public MyActionProvider(Context context) { super(context); // TODO Auto-generated constructor stub mContext = context; } @Override public View onCreateActionView() { // TODO Auto-generated method stub return null; } @Override public boolean hasSubMenu() { // TODO Auto-generated method stub return true; } @Override public void onPrepareSubMenu(SubMenu subMenu) { // TODO Auto-generated method stub //清除子菜单实例 subMenu.clear(); //从XML文件中添加MenuItem MenuInflater menuInflater = new MenuInflater(mContext); menuInflater.inflate(R.menu.provider_submenu, subMenu); //为各项MenuItem设置事件监听 for(int i = 0;i < subMenu.size();i++){ subMenu.getItem(i).setOnMenuItemClickListener(mProviderOnMenuItemClickListener); } } private class MyProviderOnMenuItemClickListener implements OnMenuItemClickListener { @Override public boolean onMenuItemClick(MenuItem item) { // TODO Auto-generated method stub mSubMenuItemClickListener.onSubMenuItem(item.getItemId()); return true; } } }
接着在ScreenFirstActivity类中实现SubMenuItemClickListener回调接口:
public class ScreenFirstActivity extends BaseActivity implements SubMenuItemClickListener{
然后在重写onSubMenuItem(int itemId)方法,具体代码如下:
@Override public void onSubMenuItem(int itemId) { // TODO Auto-generated method stub switch (itemId) { case R.id.user_like: showInformation("点赞评论"); break; case R.id.user_fuck: showInformation("Fuck评论"); break; default: break; } }
最后在onCreateOptionsMenu(Menu menu) 中获取MyActionProvider对象并设置事件监听,具体代码如下:
/** * 获取MyActionProvider对象,并设置事件监听 */ MenuItem writeMenuItem = menu.findItem(R.id.action_write); MyActionProvider myActionProvider = (MyActionProvider)writeMenuItem.getActionProvider(); myActionProvider.setOnSubMenuItemClickListener(this);
至此,自定义ActionProvider的操作便执行完毕。
public class ActionBarTabListener<T extends Fragment> implements TabListener { private Fragment mFragment; private Class<T> mFragmentClass; private String fragmentTag; private Activity mActivity; public ActionBarTabListener(Activity mActivity,String fragmentTag,Class<T> mFragmentClass){ this.mActivity = mActivity; this.mFragmentClass = mFragmentClass; this.fragmentTag = fragmentTag; } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { // TODO Auto-generated method stub //如果Fragment的实例对null,则重新创建 if(mFragment == null){ //根据类名初始化Fragment对象 mFragment = Fragment.instantiate(mActivity, mFragmentClass.getName()); ft.add(android.R.id.content, mFragment,fragmentTag); }else{ //当选中的Tab所对应的Fragment不为null时,则建立与Tab的依赖 ft.attach(mFragment); } } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { //当Tab别切换到另一个Tab,依附在当前Tab的Fragment如果不为null,则解除依赖 if(mFragment != null){ ft.detach(mFragment); } } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { // TODO Auto-generated method stub } }
//2、设置导航模式 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); //3、创建ActionBar.Tab对象,为其设置ActionBar.TabListener监听器,并设置Tab的标题名称或图标 Tab mTabApp = mActionBar .newTab() .setText("应用") .setTabListener(new ActionBarTabListener<ApplicationFragment>(this, "application", ApplicationFragment.class)); Tab mTabGame = mActionBar .newTab() .setText("游戏") .setTabListener(new ActionBarTabListener<GameFragment>(this, "game", GameFragment.class)); //4、将ActionBar.TAB对象添加到ActionBar中 mActionBar.addTab(mTabApp); mActionBar.addTab(mTabGame);
小结:由于Action Bar所涉及到的知识比较多,且鉴于篇幅关系,本文暂且讨论以上知识点,更多关于Action Bar的知识将在下一篇文章中进行深入讨论。先来为本文学习的知识做一个小结,本文讨论的的知识点主要包括:
(1)为页面添加ActionBar;(2)ActionBar图标和标题的修改及事件响应;(3)添加ActionBar按钮及事件响应;(4)为ActionBar添加 Drop-Down Navigation;(5)为ActionBar添加Action View;(6)为ActionBar添加Action Provider;(7)添加ActionBar Tabs。
源代码下载,请戳下面: