Android 弹无虚发之第二弹:Android ActionBar 的其它用法(搜索、分享、隐藏复杂布局,模仿Google Play,微信)

来源:互联网 发布:国家网络安全局 编辑:程序博客网 时间:2024/05/04 13:05

大年新年好啊。正是马年春节期间,到处都是年味儿啊,不知道大家有没有拿到红包呢?哈哈,不管拿到没有,今天我来为大家献上一份春节的心意,继上一篇ActionBar的讲解之后,这几天我又整理了一下我的个人笔记,在这里,把Actionbar的一些其它用法分享给大家。希望能够对大家有所帮助。好了,闲话不多说,开始进入代码的世界,GO!

1. Action View

如果大家使用过google play 或者安卓5.2版本的微信,那么想必大家都一定见过下面这张图片的布局。


看过 Android 弹无虚发之第一弹 的童鞋,一定知道,被红色边框标注的区域就是一个actionbar 的 item,如何往actionbar 里面添加item,我已经在Android 弹无虚发之第一弹 这篇文章里面说的很详细了,如果有不太熟悉的童鞋,可以参考这篇文章,系统的学习一下。

当我们点击上面红色区域的时候,我们会看到actionbar的布局效果,发生了如下变化,如下图红色区域标注所示:


大家可以看到,点击搜索图标后,actionbar原有的布局消失,取而代之的是一个搜索输入框。这种效果是如何实现的呢? 其实,这就是我们今天要讲解的其中一点,往actionbar中添加 action view。

Actionbar的显示位置明显,操作直接方便,在现在的app开发中,用的越来越多。但是Actionbar的区域有限,如果每一项的item都是一个复杂的布局,那就会使得本来简洁好看的actionbar显得非常臃肿丑陋,但是有些item的功能,必须得借助较为复杂的布局,这该如何解决这一矛盾点呢?谷神在发布android系统的时候,替我们考虑到了这一点,所以它引入了 action view 这么一个概念,我们可以给actionbar的item 设置 actionLayout或者actionViewClass这两个属性,使得该item可以指向其它的布局。actionLayout可以指向一个自定义的layout的xml文件,actionViewClass可以指向一些封装好的视图类文件。下面我贴一段代码给大家做一下示例。(考虑到要尽量兼容到android2.1版本,所以我还是使用V7这个支持包进行actionbar的开发,V7包的使用方法,详见这篇博客 Android 弹无虚发之第一弹 )

  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:title="@string/app_name"  
  5.           android:icon="@android:drawable/ic_search_category_default"  
  6.           yourapp:showAsAction="ifRoom|collapseActionView"  
  7.           yourapp:actionViewClass="android.support.v7.widget.SearchView" />  
  8. </menu>  

  1. yourapp:actionViewClass="android.support.v7.widget.SearchView"  

在这里,我们给这个item设定了actionViewClass这个属性,这里引用了SearchView这个类,这段代码的大体效果就和google play的actionbar的效果大体相同。这里,另外需要注意的一点是这个属性:

yourapp:showAsAction="ifRoom|collapseActionView"

我们设定 showAsAction这个属性的时候,加了collapseActionView这么一个参数,它的意思是说,将item引用的布局隐藏起来,当你点击该item的时候,再将其展现出来。通过这个属性,我们就可以将每个item复杂的布局隐藏起来,从而有效的节约了actionbar的布局空间。

下面我再贴一段代码,展示一下 actionLayout这个属性的设置方法

  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_otherview"  
  4.           android:title="@string/app_name"  
  5.           android:icon="@drawable/ic_launcher"  
  6.           yourapp:showAsAction="ifRoom|collapseActionView"  
  7.           yourapp:actionLayout="@layout/action_view"></item>"  
  8. </menu>  

在这段代码中,我们没有设置actionViewClass,而是设定了actionLayout这个属性,它的参数是一个我们自定义的xml布局文件,具体的布局内容见一下代码:

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="horizontal" >  
  6.   
  7.     <Button  
  8.         android:id="@+id/btn1"  
  9.         android:layout_width="0dp"  
  10.         android:layout_height="wrap_content"  
  11.         android:layout_weight="1"  
  12.         android:gravity="center"  
  13.         android:text="Button 1"  
  14.         android:textSize="8sp" />  
  15.   
  16.     <Button  
  17.         android:id="@+id/btn2"  
  18.         android:layout_width="0dp"  
  19.         android:layout_height="wrap_content"  
  20.         android:layout_weight="1"  
  21.         android:gravity="center"  
  22.         android:text="Button 2"   
  23.         android:textSize="8sp" />  
  24.   
  25.     <Button  
  26.         android:id="@+id/btn3"  
  27.         android:layout_width="0dp"  
  28.         android:layout_height="wrap_content"  
  29.         android:layout_weight="1"  
  30.         android:gravity="center"  
  31.         android:text="Button 3"   
  32.         android:textSize="8sp" />  
  33.   
  34.     <Button  
  35.         android:id="@+id/btn4"  
  36.         android:layout_width="0dp"  
  37.         android:layout_height="wrap_content"  
  38.         android:layout_weight="1"  
  39.         android:gravity="center"  
  40.         android:text="Button 4"   
  41.         android:textSize="8sp" />  
  42.   
  43. </LinearLayout>  


以上代码,就是在actionLayout中引用的布局文件,这样一来,当我们点击actionbar的item的时候,这四个button就会展现在actionbar上面,点击回退键或者BACK键,actionbar的布局又会恢复到初始的状态。当然了,无论设置哪个属性,都可以引用一个相对复杂的布局,但是一定要加上 

 yourapp:showAsAction="ifRoom|collapseActionView"这段代码的设定才行。

学会了如何设置ActionView 这种隐藏复杂布局的效果,有的童鞋就会接着问到:只是点击item后,展现复杂布局的效果还不行,我还想去响应这些复杂布局的点击事件,那我该如何处理呢?以前直接在onOptionsItemSelected()中响应item的事件就可以了,现在如何去响应这些布局的事件呢?哈哈,别急,代码马上呈现给大家,请看:

  1.     @Override  
  2.     public boolean onCreateOptionsMenu(Menu menu) {  
  3.         // Inflate the menu; this adds items to the action bar if it is present.  
  4. //        getMenuInflater().inflate(R.menu.main, menu);  
  5.         getMenuInflater().inflate(R.menu.item, menu);  
  6.         MenuItem item = menu.findItem(R.id.action_otherview);  
  7.         View view = MenuItemCompat.getActionView(item);  
  8.           
  9. //      对于API 11 以及以上的版本,获取ActionView直接调用以下代码即可  
  10. //      View view = item.getActionView();  
  11.           
  12.         Button btn1 = (Button)view.findViewById(R.id.btn1);  
  13.         btn1.setOnClickListener(new OnClickListener() {  
  14.               
  15.             @Override  
  16.             public void onClick(View v) {  
  17.                 Toast.makeText(MainActivity.this"哈哈,我点击了第一个Button", Toast.LENGTH_SHORT).show();  
  18.             }  
  19.         });  
  20.         return true;  
  21.     }  

我们在 onCreateOptionsMenu 这个方法中,获取相对应的item,然后通过getActionView()这个方法,获取复杂布局的引用,接下来的工作,就如上面代码所示,就是我们经常用到的控件初始化,然后设置点击事件了,想必大家已经熟练的不能再熟练了。在代码中,我用了一个Button作为示例,重写了它的点击事件,大家在平时的开发过程中,可以根据自己的业务逻辑,去做相应的处理。

另外,当item的 actionView 展开和隐藏的时候,我们也许需要针对这两个状态的变化,进行一些逻辑控制和界面的更新,那么我们可以在 onCreateOptionsMenu 这个方法中,去监听item的展开事件和隐藏事件,具体的代码如下所示:

  1. @Override  
  2. public boolean onCreateOptionsMenu(Menu menu) {  
  3.     // Inflate the menu; this adds items to the action bar if it is present.  
  4.       getMenuInflater().inflate(R.menu.main, menu);  
  5.     getMenuInflater().inflate(R.menu.item, menu);  
  6.     MenuItem item = menu.findItem(R.id.action_otherview);  
  7.      
  8.     MenuItemCompat.setOnActionExpandListener(item, new OnActionExpandListener() {  
  9.         @Override  
  10.         public boolean onMenuItemActionCollapse(MenuItem item) {  
  11.             Toast.makeText(MainActivity.this"啊哦,我隐藏起来了!", Toast.LENGTH_SHORT).show();  
  12.             return true;  
  13.         }  
  14.   
  15.         @Override  
  16.         public boolean onMenuItemActionExpand(MenuItem item) {  
  17.             Toast.makeText(MainActivity.this"啦啦啦,我出现喽!", Toast.LENGTH_SHORT).show();  
  18.             return true;  
  19.         }  
  20.     });  
  21.       
  22.     return true;  
  23. }  

2. Action Provider

我们常常在一个actionbar的界面当中,会发现一个分享按钮,希望能够把你感兴趣的文字、图片等,分享给你的好友。比如下面这幅截图,在手机相册当中,就有这么一个功能。


这个就是actionbar另外一个用法,类似于action view,这种形式叫做Action Provider,其中有两种用法,一种是使用系统提供的分享组件ShareActionProvider,一种是继承

ActionProvider.这个父类,然后重写里面的实现,自定义布局和响应事件。下面我就分别介绍这两种用法。

1.ShareActionProvider

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <menu xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:yourapp="http://schemas.android.com/apk/res-auto" >  
  4.   
  5.     <item  
  6.         android:id="@+id/action_share"  
  7.         android:title="@string/app_name"  
  8.         yourapp:actionProviderClass="android.support.v7.widget.ShareActionProvider"  
  9.         yourapp:showAsAction="ifRoom"/>  
  10.   
  11. </menu>  

在这段menu的xml文件中,我们设定actionProviderClass 这个属性为 V7包自带的分享组件 ShareActionProvider。接下来,我们来看看,在java代码中,是如何引用这个xml文件并且进行设置的。

  1. //下面的代码是使用系统的shareprovider,需要设定分享的intent。  
  2.         getMenuInflater().inflate(R.menu.shareprovider, menu);  
  3.         MenuItem shareItem = menu.findItem(R.id.action_share);  
  4.         ShareActionProvider mShareActionProvider = (ShareActionProvider)  
  5.                 MenuItemCompat.getActionProvider(shareItem);  
  6.         mShareActionProvider.setShareIntent(getDefaultIntent());  

  1. private Intent getDefaultIntent() {  
  2.     Intent intent = new Intent(Intent.ACTION_SEND);  
  3.        intent.setType("text/plain");    
  4.        intent.putExtra(Intent.EXTRA_SUBJECT, "分享");     
  5.        intent.putExtra(Intent.EXTRA_TEXT, "你好 ");    
  6.        intent.putExtra(Intent.EXTRA_TITLE, "我是标题");  
  7.     return intent;  
  8. }  

在onCreateOptionsMenu这个方法中,我们先解析这个menu的xml文件,然后通过menuitem,获取在xml文件中,设定好的ShareActionProvider,然后通过 setShareIntent这个方法,设置分享Intent的各种意图,在这里,我举例分享的是几段文字,大家也可以分享图片或者其他的东西,只需要在 intent.setType 这个方法中,更换一下分享类型就可以了。这样设置完成后,当你点击这个分享按钮的时候,系统就会将手机内,所以具有分享功能的app,都给你罗列出来,供你选择。另外,还有一点需要注意一下,请看下图:


请注意红色边框标注的区域,在最初始的状态下,这里是不显示这一项的。当你通过shareprovider分享过之后,系统会将你经常使用的分享App,直接显示在这里,比如说,你经常使用Gmail分享内容,那么在actionbar的这个位置,就会如图中所示,直接将Gmail的图标显示在这里,以后可以直接点击这个图标进行分享,而不需要再在下拉菜单中选择了。系统排序这些分享列表的信息,会默认存放在DEFAULT_SHARE_HISTORY_FILE_NAME.这个文件中。如果在你的app当中,这个ShareActionProvider每次分享的含义和内容不一样,你希望默认分享的那个图标,以及分享列表的排序能够做出相应的变化,那么你需要设置如下代码,当你的分享状态发生变化的时候,不在使用默认的这个DEFAULT_SHARE_HISTORY_FILE_NAME.文件,而是通过代码设置,自定义一个名称的文件,如下所示:

  1. //将存放分享列表排序信息的文件更换,不在使用默认的那个,名称可以自己随便定义  
  2. mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");  

以上内容就是使用系统自带的 ShareActionProvider 进行分享信息的方法。接下来,我给大家介绍,如何继承ActionProvider,自定义一个分享action。首先,我们需要先定义一个内部类,继承 ActionProvider,然后重点重写三个方法,ActionProvider()、onCreateActionView()、onPerformDefaultAction(),看一下代码吧:

  1. public static class SettingsActionProvider extends ActionProvider {  
  2.   
  3.         /** An intent for launching the system settings. */  
  4.   
  5.         /** Context for accessing resources. */  
  6.         private final Context mContext;  
  7.   
  8.         /** 
  9.          * Creates a new instance. 
  10.          * 
  11.          * @param context Context for accessing resources. 
  12.          */  
  13.         public SettingsActionProvider(Context context) {  
  14.             super(context);  
  15.             mContext = context;  
  16.         }  
  17.         @Override  
  18.         public boolean onPerformDefaultAction() {  
  19.             // This is called if the host menu item placed in the overflow menu of the  
  20.             // action bar is clicked and the host activity did not handle the click.  
  21. //            mContext.startActivity(sSettingsIntent);  
  22.               Intent intent=new Intent(Intent.ACTION_SEND);     
  23.               intent.setType("text/plain");     
  24.               intent.putExtra(Intent.EXTRA_SUBJECT, "分享");     
  25.               intent.putExtra(Intent.EXTRA_TEXT, "终于可以了!!!");      
  26.               intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);     
  27.               mContext.startActivity(Intent.createChooser(intent, ""));    
  28.             return true;  
  29.         }  
  30.   
  31.         @Override  
  32.         public View onCreateActionView() {  
  33.             LayoutInflater layoutInflater = LayoutInflater.from(mContext);  
  34.             View view = layoutInflater.inflate(R.layout.custom_provider_layout, null);  
  35.             ImageButton button = (ImageButton) view.findViewById(R.id.custom_share_btn);  
  36.             // Attach a click listener for launching the system settings.  
  37.             button.setOnClickListener(new View.OnClickListener() {  
  38.                 @Override  
  39.                 public void onClick(View v) {  
  40.                   Intent intent=new Intent(Intent.ACTION_SEND);     
  41.                   intent.setType("text/plain");     
  42.                   intent.putExtra(Intent.EXTRA_SUBJECT, "分享");     
  43.                   intent.putExtra(Intent.EXTRA_TEXT, "终于可以了!!!");      
  44.                   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);     
  45.                   mContext.startActivity(Intent.createChooser(intent, ""));  
  46.                 }  
  47.             });  
  48.             return view;  
  49.         }  
  50.     }  

在onCreateActionView()方法中,我们解析了一个我们自定义的布局文件,然后给其中的一个ImageButton,设置了点击事件,当我们点击这个按钮的时候,就会执行它的Onclick事件,然后发送一个分享的Intent,同样的,系统会将手机内,带有分享属性的app都罗列出来,供你选择。既然自定义了一个内部类,那么如何在xml文件当中引用它呢?其实很简单,跟系统的引用方式大体相同,只不过更换了包名类名,并且用一个$符号来连接内部类,看代码:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <menu xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:yourapp="http://schemas.android.com/apk/res-auto" >  
  4.   
  5.     <item  
  6.         android:id="@+id/action_share_custom"  
  7.         android:title="@string/app_name"  
  8.         yourapp:actionProviderClass="com.example.myactionbar.MainActivity$SettingsActionProvider"  
  9.         yourapp:showAsAction="ifRoom"/>  
  10.   
  11. </menu>  


其实讲到这里,大家应该注意到,其实在onclick事件当中,我们可以随意设置我们的点击事件,不一定是分享内容,也可以跳转指定的界面等等。总之,自定义的ActionProvider 不如系统自带的方便简洁,但是可扩展性很强,可以有效的满足开发过程中的业务逻辑需要。


以上内容,就是我想跟大家分享的内容,主要介绍了一下,actionbar的分享机制和隐藏复杂布局的机制,虽然大家在开发当中,可以使用完全自定义的actionbar进行开发,但是如果能够掌握系统给我们提供好的这些API,那么不仅可以减少我们的代码量,也使得我们以后的扩展和维护的工作减少了不少的负担,更重要的是,多了解一些系统的API,对我们开发的思路和阅读源码的能力,也是一种很好的锻炼和提高啊,你说,是不?

本篇博客的讲解代码,同样打包完成,上传到了csdn资源库,下载地址如下:

http://download.csdn.net/detail/pringlee2011/6895339

0 0
原创粉丝点击