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

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

1. Action View

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

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

看过 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的界面当中,会发现一个分享按钮,希望能够把你感兴趣的文字、图片等,分享给你的好友。比如下面这幅截图,在手机相册当中,就有这么一个功能。

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

这个就是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,都给你罗列出来,供你选择。另外,还有一点需要注意一下,请看下图:

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

请注意红色边框标注的区域,在最初始的状态下,这里是不显示这一项的。当你通过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资源库,下载地址如下:

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

你可能感兴趣的:(android,Provider,view,action,action,Actionbar,Drop-down)