大年新年好啊。正是马年春节期间,到处都是年味儿啊,不知道大家有没有拿到红包呢?哈哈,不管拿到没有,今天我来为大家献上一份春节的心意,继上一篇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 弹无虚发之第一弹 )
<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:title="@string/app_name" android:icon="@android:drawable/ic_search_category_default" yourapp:showAsAction="ifRoom|collapseActionView" yourapp:actionViewClass="android.support.v7.widget.SearchView" /> </menu>
yourapp:actionViewClass="android.support.v7.widget.SearchView"
在这里,我们给这个item设定了actionViewClass这个属性,这里引用了SearchView这个类,这段代码的大体效果就和google play的actionbar的效果大体相同。这里,另外需要注意的一点是这个属性:
yourapp:showAsAction="ifRoom|collapseActionView"
我们设定 showAsAction这个属性的时候,加了collapseActionView这么一个参数,它的意思是说,将item引用的布局隐藏起来,当你点击该item的时候,再将其展现出来。通过这个属性,我们就可以将每个item复杂的布局隐藏起来,从而有效的节约了actionbar的布局空间。
下面我再贴一段代码,展示一下 actionLayout这个属性的设置方法
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yourapp="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_otherview" android:title="@string/app_name" android:icon="@drawable/ic_launcher" yourapp:showAsAction="ifRoom|collapseActionView" yourapp:actionLayout="@layout/action_view"></item>" </menu>
在这段代码中,我们没有设置actionViewClass,而是设定了actionLayout这个属性,它的参数是一个我们自定义的xml布局文件,具体的布局内容见一下代码:
<?xml version="1.0" encoding="UTF-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <Button android:id="@+id/btn1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="Button 1" android:textSize="8sp" /> <Button android:id="@+id/btn2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="Button 2" android:textSize="8sp" /> <Button android:id="@+id/btn3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="Button 3" android:textSize="8sp" /> <Button android:id="@+id/btn4" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="Button 4" android:textSize="8sp" /> </LinearLayout>
以上代码,就是在actionLayout中引用的布局文件,这样一来,当我们点击actionbar的item的时候,这四个button就会展现在actionbar上面,点击回退键或者BACK键,actionbar的布局又会恢复到初始的状态。当然了,无论设置哪个属性,都可以引用一个相对复杂的布局,但是一定要加上
yourapp:showAsAction="ifRoom|collapseActionView"这段代码的设定才行。
学会了如何设置ActionView 这种隐藏复杂布局的效果,有的童鞋就会接着问到:只是点击item后,展现复杂布局的效果还不行,我还想去响应这些复杂布局的点击事件,那我该如何处理呢?以前直接在onOptionsItemSelected()中响应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); getMenuInflater().inflate(R.menu.item, menu); MenuItem item = menu.findItem(R.id.action_otherview); View view = MenuItemCompat.getActionView(item); // 对于API 11 以及以上的版本,获取ActionView直接调用以下代码即可 // View view = item.getActionView(); Button btn1 = (Button)view.findViewById(R.id.btn1); btn1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "哈哈,我点击了第一个Button", Toast.LENGTH_SHORT).show(); } }); return true; }
我们在 onCreateOptionsMenu 这个方法中,获取相对应的item,然后通过getActionView()这个方法,获取复杂布局的引用,接下来的工作,就如上面代码所示,就是我们经常用到的控件初始化,然后设置点击事件了,想必大家已经熟练的不能再熟练了。在代码中,我用了一个Button作为示例,重写了它的点击事件,大家在平时的开发过程中,可以根据自己的业务逻辑,去做相应的处理。
另外,当item的 actionView 展开和隐藏的时候,我们也许需要针对这两个状态的变化,进行一些逻辑控制和界面的更新,那么我们可以在 onCreateOptionsMenu 这个方法中,去监听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); getMenuInflater().inflate(R.menu.item, menu); MenuItem item = menu.findItem(R.id.action_otherview); MenuItemCompat.setOnActionExpandListener(item, new OnActionExpandListener() { @Override public boolean onMenuItemActionCollapse(MenuItem item) { Toast.makeText(MainActivity.this, "啊哦,我隐藏起来了!", Toast.LENGTH_SHORT).show(); return true; } @Override public boolean onMenuItemActionExpand(MenuItem item) { Toast.makeText(MainActivity.this, "啦啦啦,我出现喽!", Toast.LENGTH_SHORT).show(); return true; } }); return true; }
2. Action Provider
我们常常在一个actionbar的界面当中,会发现一个分享按钮,希望能够把你感兴趣的文字、图片等,分享给你的好友。比如下面这幅截图,在手机相册当中,就有这么一个功能。
这个就是actionbar另外一个用法,类似于action view,这种形式叫做Action Provider,其中有两种用法,一种是使用系统提供的分享组件ShareActionProvider
,一种是继承
ActionProvider
.这个父类,然后重写里面的实现,自定义布局和响应事件。下面我就分别介绍这两种用法。
1.ShareActionProvider
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yourapp="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_share" android:title="@string/app_name" yourapp:actionProviderClass="android.support.v7.widget.ShareActionProvider" yourapp:showAsAction="ifRoom"/> </menu>
在这段menu的xml文件中,我们设定actionProviderClass 这个属性为 V7包自带的分享组件 ShareActionProvider。接下来,我们来看看,在java代码中,是如何引用这个xml文件并且进行设置的。
//下面的代码是使用系统的shareprovider,需要设定分享的intent。 getMenuInflater().inflate(R.menu.shareprovider, menu); MenuItem shareItem = menu.findItem(R.id.action_share); ShareActionProvider mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem); mShareActionProvider.setShareIntent(getDefaultIntent());
private Intent getDefaultIntent() { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, "分享"); intent.putExtra(Intent.EXTRA_TEXT, "你好 "); intent.putExtra(Intent.EXTRA_TITLE, "我是标题"); return intent; }
在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
.文件,而是通过代码设置,自定义一个名称的文件,如下所示:
//将存放分享列表排序信息的文件更换,不在使用默认的那个,名称可以自己随便定义 mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
public static class SettingsActionProvider extends ActionProvider { /** An intent for launching the system settings. */ /** Context for accessing resources. */ private final Context mContext; /** * Creates a new instance. * * @param context Context for accessing resources. */ public SettingsActionProvider(Context context) { super(context); mContext = context; } @Override public boolean onPerformDefaultAction() { // This is called if the host menu item placed in the overflow menu of the // action bar is clicked and the host activity did not handle the click. // mContext.startActivity(sSettingsIntent); Intent intent=new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, "分享"); intent.putExtra(Intent.EXTRA_TEXT, "终于可以了!!!"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(Intent.createChooser(intent, "")); return true; } @Override public View onCreateActionView() { LayoutInflater layoutInflater = LayoutInflater.from(mContext); View view = layoutInflater.inflate(R.layout.custom_provider_layout, null); ImageButton button = (ImageButton) view.findViewById(R.id.custom_share_btn); // Attach a click listener for launching the system settings. button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, "分享"); intent.putExtra(Intent.EXTRA_TEXT, "终于可以了!!!"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(Intent.createChooser(intent, "")); } }); return view; } }
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yourapp="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_share_custom" android:title="@string/app_name" yourapp:actionProviderClass="com.example.myactionbar.MainActivity$SettingsActionProvider" yourapp:showAsAction="ifRoom"/> </menu>
其实讲到这里,大家应该注意到,其实在onclick事件当中,我们可以随意设置我们的点击事件,不一定是分享内容,也可以跳转指定的界面等等。总之,自定义的ActionProvider 不如系统自带的方便简洁,但是可扩展性很强,可以有效的满足开发过程中的业务逻辑需要。
以上内容,就是我想跟大家分享的内容,主要介绍了一下,actionbar的分享机制和隐藏复杂布局的机制,虽然大家在开发当中,可以使用完全自定义的actionbar进行开发,但是如果能够掌握系统给我们提供好的这些API,那么不仅可以减少我们的代码量,也使得我们以后的扩展和维护的工作减少了不少的负担,更重要的是,多了解一些系统的API,对我们开发的思路和阅读源码的能力,也是一种很好的锻炼和提高啊,你说,是不?
本篇博客的讲解代码,同样打包完成,上传到了csdn资源库,下载地址如下:
http://download.csdn.net/detail/pringlee2011/6895339