开源项目MultiChoiceAdapter详解(一)——概要介绍
项目地址:https://github.com/ManuelPeinado/MultiChoiceAdapter
这个项目主要是提供了一个多选适配器,使用者可以用它来替换传统的适配器,用途还算比较广泛。但是,但是……这个开源项目写的真的挺不好的,它大量使用了ActionMode,基本都是讲ActionMode和Adapter写到一起了,扩展性十分的低。而且这里面还有各种各样的小细节需要注意的,比如返回值啦,或者是控件的定义方式,是否要用自定义控件什么的了。在官方文档的介绍中说各种简单和实用,其实真正用下来发现学它比学其他的框架要难三倍以上,原版的项目很不推荐使用。所以这里我自己讲这个开源项目进行了改进,即确保不变动原来的使用方式,又增加了扩展性,所以极力推荐用我改写的项目来实现!本篇先进行简要的介绍下原有的功能,和我添加的功能。
一、自定义控件
我把自定义控件用包名进行了分割,大家可以明显的看出这个项目自定义了这几个控件。这些控件主要是作为adapter中item视图来用的。一般我们的item.xml文件中会有多个控件,所以我一般推荐是用一些像是CheckableLinearLayout进行包裹住这些控件,至于CheckabeRelativeLayout,CheckableFrameLayout这样的看情况吧。其中,CheckableImageView主要是用于item中有imageview的情况,有的话就把imageview替换为这个吧。
example01:
<?xml version="1.0" encoding="utf-8"?> <com.manuelpeinado.multichoiceadapter.view.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/custom_list_item_background" android:orientation="horizontal"> <!-- 上面必须要用自定义的layout,否则不会有选中的效果!!! -->
……
…… 这里放其他的控件
…… </com.manuelpeinado.multichoiceadapter.view.CheckableLinearLayout>
这里还需要注意,我们应该在这个控件的background属性中定义一个selector,用于表示选择的状态。如果这里不进行设置,那么就要在代码中进行设置,我个人推荐还是在这里进行设置吧。因为选择效果的话一般是没有太大变动的需求的。
example02:
<?xml version="1.0" encoding="utf-8"?> <com.manuelpeinado.multichoiceadapter.view.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/custom_list_item_background"> <com.manuelpeinado.multichoiceadapter.view.CheckableImageView android:id="@+id/item_imageView" android:layout_width="match_parent" android:layout_height="250dp" android:scaleType="centerCrop" /> </com.manuelpeinado.multichoiceadapter.view.CheckableLinearLayout>
上面这个例子是用作一个类似于瀑布流那样的,全是图片的多选界面的。顺便说下CheckableTextView在android中已经提供了,可以直接使用。其实说白了,这些控件就是实现了Checkable接口而已,没太大特别的地方。下面贴个源码,比较能有直观的理解。
CheckableImageView.java源码
package com.manuelpeinado.multichoiceadapter.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.StateListDrawable; import android.util.AttributeSet; import android.widget.Checkable; import android.widget.ImageView; import com.manuelpeinado.multichoiceadapter.R; public class CheckableImageView extends ImageView implements Checkable { private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked }; private StateListDrawable stateList; private boolean mChecked; public CheckableImageView(Context context) { super(context); } public CheckableImageView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckableImageView, R.attr.checkableImageViewStyle, R.style.MultiChoiceAdapter_DefaultCheckableImageViewStyle); stateList = (StateListDrawable)a.getDrawable(R.styleable.CheckableImageView_android_foreground); a.recycle(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (stateList != null) { stateList.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); stateList.draw(canvas); } } /**************************/ /** Checkable **/ /**************************/ @Override public boolean isChecked() { return mChecked; } @Override public void setChecked(boolean checked) { if (mChecked != checked) { mChecked = checked; refreshDrawableState(); } } @Override public void toggle() { setChecked(!isChecked()); } /**************************/ /** Drawable States **/ /**************************/ @Override public int[] onCreateDrawableState(int extraSpace) { final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); if (isChecked()) { mergeDrawableStates(drawableState, CHECKED_STATE_SET); } return drawableState; } @Override protected void drawableStateChanged() { super.drawableStateChanged(); if (stateList != null) { int[] myDrawableState = getDrawableState(); stateList.setState(myDrawableState); invalidate(); } } }
二、适配器和接口
详细解释 ↓:
监听器源码
OnSelectedStateChangeListener.java
package com.manuelpeinado.multichoiceadapter.base; /** * @author:Jack Tony * @tips :监听适配器选中item状态的监听器 * @date :2014-10-20 */ public interface OnSelectedStateChangeListener { /** * @param checkedItemCount 已经选中的item数目 */ public void onSelectedStateChanged(int checkedItemCount) ; }
其余的源码请下载项目后自行查看,我主要改的是helper中的内容,改的比较多可以和原来项目对比着看看。
三、适配器用法
现在我们已经看到了它提供了三个适配器MultiChoiceArrayAdapter,MultiChoiceBaseAdapter,MultiChoiceSimpleCursorAdapter。还有一个我自己写的MulitChoiceNormalArrayAdapter(简单实现了MultiChoiceArrayAdapter,用法之后会说到),我们很容易和常用的适配器进行联系起来。但是它的用法是十分奇葩的,略微诡异。
String[] data = {"android","ios","wp","c++","java","c#","javascript","vb","delphi","PB","ASP","SQL"}; ListView actionModelistView = (ListView)findViewById(R.id.actionMode_listView); actionModeAdapter = new TestAdapter(savedInstanceState, this,R.layout.item, R.id.item_textView, data); actionModeAdapter.setAdapterView(actionModelistView); actionModeAdapter.setOnItemClickListener(new MyItemClick(actionModeAdapter));
String[] data = {"android","ios","wp","c++","java","c#","javascript","vb","delphi","PB","ASP","SQL"};
ListView actionModelistView = (ListView)findViewById(R.id.actionMode_listView);
actionModeAdapter = new TestAdapter(savedInstanceState, this,R.layout.item, R.id.item_textView, data);//初始化
actionModeAdapter.setAdapterView(actionModelistView);//不用listview的setAdapter,而是让适配器来setView
actionModeAdapter.setOnItemClickListener(new MyItemClick(actionModeAdapter));//连添加监听器也是用适配器进行添加的
下面的几篇文章中会用到ActionMode的配置文件
在res->values->menu下建立一个my_action_mode.xml文件
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_share" android:icon="@drawable/ic_social_share" android:showAsAction="always" android:title="分享"/> <item android:id="@+id/menu_discard" android:icon="@drawable/ic_content_discard" android:showAsAction="always" android:title="取消选择"/> </menu>
开源项目下载:http://download.csdn.net/detail/shark0017/8065279
注:里面以Lib_xxx开头的就是我自己修改的,另一个是原始文件。
开源项目MultiChoiceAdapter详解(一)——概要介绍
开源项目MultiChoiceAdapter详解(二)——MultiChoiceArrayAdapter的使用
开源项目MultiChoiceAdapter详解(三)——MulitChoiceNormalArrayAdapter的使用
开源项目MultiChoiceAdapter详解(四)——MultiChoiceBaseAdapter的使用
开源项目MultiChoiceAdapter详解(五)——可扩展的MultiChoiceBaseAdapter
开源项目MultiChoiceAdapter详解(六)——GridView和MultiChoiceBaseAdapter配合使用