开源项目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配合使用

原文地址:https://www.cnblogs.com/tianzhijiexian/p/4041400.html