大年新年好啊。正是马年春节期间,到处都是年味儿啊,不知道大家有没有拿到红包呢?哈哈,不管拿到没有,今天我来为大家献上一份春节的心意,继上一篇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
.这个父类,然后重写里面的实现,自定义布局和响应事件。下面我就分别介绍这两种用法。
- <?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");
以上内容就是使用系统自带的 ShareActionProvider 进行分享信息的方法。接下来,我给大家介绍,如何继承ActionProvider,自定义一个分享action。首先,我们需要先定义一个内部类,继承 ActionProvider,然后重点重写三个方法,ActionProvider()、onCreateActionView()、onPerformDefaultAction(),看一下代码吧:
- 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;
- }
- }
在onCreateActionView()方法中,我们解析了一个我们自定义的布局文件,然后给其中的一个ImageButton,设置了点击事件,当我们点击这个按钮的时候,就会执行它的Onclick事件,然后发送一个分享的Intent,同样的,系统会将手机内,带有分享属性的app都罗列出来,供你选择。既然自定义了一个内部类,那么如何在xml文件当中引用它呢?其实很简单,跟系统的引用方式大体相同,只不过更换了包名类名,并且用一个$符号来连接内部类,看代码:
- <?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资源库,下载地址如下: