本文主要介绍Android Support v7提供的RecycleView和交错式布局(通常成为瀑布流布局)的使用和事件监听处理。

  1. 涉及到开源库有:

    : 

   Facebook开源的不是一般强大的图片加载组件库 

    : 

   Android View和事件绑定库,通过注解完成,在编译时APT处理注解文档。

  

  2. 模块配置

    

   Android Studio模块,build.gradle配置:

   

apply plugin: 'com.android.application'android {    compileSdkVersion 21    buildToolsVersion '21.1.2'    defaultConfig {        applicationId 'secondriver.sdk'        minSdkVersion 16        targetSdkVersion 21        versionCode 1        versionName '1.0'    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }    packagingOptions {        exclude 'META-INF/services/javax.annotation.processing.Processor'    }    lintOptions {        disable 'InvalidPackage'    }}dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    compile 'com.android.support:appcompat-v7:21.0.3'    compile 'com.android.support:recyclerview-v7:21.0.3@aar'    compile 'com.android.support:cardview-v7:21.0.3@aar'    compile 'com.facebook.fresco:fresco:0.8.0'    compile 'com.jakewharton:butterknife:7.0.1'    testCompile 'junit:junit:4.12'}

   3. 布局文件

    主布局文件:activity_recycleview.xml 包含一个RecycleView,将作为主屏幕组件。

   

    

    RecycleView 通过设置不同的布局管理器对象来实现不同的布局显示,如:   

    android.support.v7.widget.LinearLayoutManager 可以实现ListView的布局效果

    android.support.v7.widget.GridLayoutManager  可以实现GridView的布局效果

    android.support.v7.widget.StaggeredGridLayoutManager 可以实现交错式网格布局效果

    次布局文件(RecycleView中显示的每一项视图的布局):item_recycelview.xml 通过com.android.support:CardView包提供的CardView帧式容器布局包含一个ImageView和TextView作为RecycleView的每一项视图的布局。

    

    
        
            
            
            

    

    ImageView组件使用的是Fresco库提供的视图组件。

 4. Activity实现和数据填充

    4.1 RecycleView中的每一项视图的数据组成

       文本信息+ 图片地址(url,file,resId) 本示例中采用Url网络图片

       

/**     * View项的数据对象     */    static class Pair {        public String text;        public String url;        public Pair(String text, String url) {            this.text = text;            this.url = url;        }    }

        

   

    4.2 RecycleView中国的每一项视图的数据填充,即适配器

        自定义适配器需要实现RecycleView.Adapter类。

  

static class RecycleViewAdapter extends RecyclerView.Adapter
 {        /**         * RecycleView的View项单击事件监听         */        public interface OnRecycleViewItemClickListener {            void onRecycleViewItemClick(View view, int position);        }        private ArrayList
 items = new ArrayList<>();        private OnRecycleViewItemClickListener mOnRecycleViewItemClickListener;        public RecycleViewAdapter(ArrayList
 items) {            this.items = items;        }        @Override        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview, parent, false);            return new RecycleViewItemHolder(view, mOnRecycleViewItemClickListener);        }        @Override        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {            Pair pair = items.get(position);            ((RecycleViewItemHolder) holder).setContent(pair);        }        @Override        public int getItemCount() {            return items.size();        }        public void setOnRecycleViewItemClickListener(OnRecycleViewItemClickListener onItemClickListener) {            if (null != onItemClickListener) {                this.mOnRecycleViewItemClickListener = onItemClickListener;            }        }    }

   主要实现onCreateViewHolder和onBindViewHolder方法。由于RecycleView并未提供为视图项添加监听事件,这里自定义个一个事件监听接口,在实例化适配器的时候可以选择设置事件监听。

   4.3 创建ViewHolder需要通过自定义ViewHolder类继承RecycleView.ViewHolder。

  

static class RecycleViewItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {        @Bind(R.id.info_text)        public TextView infoTextView;        @Bind(R.id.info_p_w_picpath)        public SimpleDraweeView draweeView;        private RecycleViewAdapter.OnRecycleViewItemClickListener onItemClickListener;        public RecycleViewItemHolder(View itemView, RecycleViewAdapter.OnRecycleViewItemClickListener onItemClickListener) {            super(itemView);            ButterKnife.bind(this, itemView);            this.onItemClickListener = onItemClickListener;            itemView.setOnClickListener(this);        }        public void setContent(Pair pair) {            infoTextView.setText(pair.text);            draweeView.setImageURI(Uri.parse(pair.url));        }        @Override        public void onClick(View v) {            if (null != onItemClickListener) {                onItemClickListener.onRecycleViewItemClick(v, getPosition());            }        }    }

    在构造方法中的传入OnRecycleViewItemClickListener对象,并且自定义ViewHolder实现OnClickListener接口,通过为itemView对象设置OnClickListener监听事件,在onClick方法中将点击事件的处理交由OnRecycleViewItemClickListener对象处理,从而达到为RecycleView中的itemView注册点击事件。

    如果不采用这种方式添加事件监听,就不需要自定义监听接口和自定义ViewHolder实现事件监听接口以及事件处理。另外可以通过获得的itemView之后,通过组件I的获取组件来添加事件监听。还可以通过获得的自定义ViewHolder,来访问每个组件。

   4.4 Activity的具体实现

    

package secondriver.sdk.activity;import android.app.Activity;import android.net.Uri;import android.os.Bundle;import android.support.v7.widget.DefaultItemAnimator;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.StaggeredGridLayoutManager;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import android.widget.Toast;import com.facebook.drawee.view.SimpleDraweeView;import java.util.ArrayList;import java.util.Arrays;import java.util.Random;import butterknife.Bind;import butterknife.ButterKnife;import secondriver.sdk.R;/** * Author : secondriver * Created : 2015/11/18 */public class RecycleViewActivity extends Activity {    private static final String TAG = RecyclerView.class.getName();    private static final String[] RES_URL = new String[]{            "http://p1.wmpic.me/article/2015/11/16/1447644849_hySANEEF.jpg",            //减少篇幅,此处省去14个图片Url    };    @Bind(R.id.recycler_view)    public RecyclerView mRecycleView;    private final int PRE_SCREEN_NUMBER = 6;    private final int SPAN_COUNT = 2;    private int previousLastIndex = 0;    private boolean isSlidingToLast = false;    private RecycleViewAdapter mAdapter;    private ArrayList
 mItem = new ArrayList<>();    //交错式网格布局管理对象,即通常称的瀑布流布局    private StaggeredGridLayoutManager mLayoutManager;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_recyclerview);        ButterKnife.bind(this); Fresco.initialize(this); //重要,Fresco做一系列初始化工作        initRecycleView();    }    private void initRecycleView() {        mLayoutManager = new StaggeredGridLayoutManager(SPAN_COUNT, StaggeredGridLayoutManager.VERTICAL);        mRecycleView.setLayoutManager(mLayoutManager);        mAdapter = new RecycleViewAdapter(mItem);        loadData(false);        mRecycleView.setAdapter(mAdapter);        mRecycleView.setItemAnimator(new DefaultItemAnimator());        //RecycleView的View项单击事件监听        mAdapter.setOnRecycleViewItemClickListener(new RecycleViewAdapter.OnRecycleViewItemClickListener() {            @Override            public void onRecycleViewItemClick(View view, int position) {                long id = mRecycleView.getChildItemId(view);                Log.d(TAG, "View项的根视图:" + view.getClass().getName() + ",position=" + position + " ViewHolder_Id=" + id);                //通过findViewById查找View项中的元素                SimpleDraweeView draweeView = (SimpleDraweeView) view.findViewById(R.id.info_p_w_picpath);                if (null != draweeView) {                    draweeView.setImageURI(Uri.parse(RES_URL[0]));                    Toast.makeText(RecycleViewActivity.this, "通过findViewById查找View项中的元素", Toast.LENGTH_LONG).show();                }                RecycleViewItemHolder recycleViewItemHolder = (RecycleViewItemHolder) mRecycleView.findViewHolderForPosition(position);                if (null != recycleViewItemHolder) {                    recycleViewItemHolder.infoTextView.setText("通过ViewHolder找到View项中的元素");                }            }        });        //下拉刷新,追加内容        mRecycleView.setOnScrollListener(                new RecyclerView.OnScrollListener() {                    @Override                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                        super.onScrollStateChanged(recyclerView, newState);                        if (newState == RecyclerView.SCROLL_STATE_IDLE) {                            if (isPullToBottom() && isSlidingToLast) {                                if (mItem.size() > 36) { //最大数据量                                    Toast.makeText(RecycleViewActivity.this, "没有数据了", Toast.LENGTH_LONG).show();                                    return;                                } else {                                    loadData(false);                                    Log.d(TAG, "notifyItemRangeInserted startPosition=" + previousLastIndex);                                    mAdapter.notifyItemRangeInserted(previousLastIndex, PRE_SCREEN_NUMBER);                                }                            }                        }                        if (newState == RecyclerView.SCROLL_STATE_SETTLING) {                            Log.d(TAG, "settling");                        }                    }                    @Override                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                        super.onScrolled(recyclerView, dx, dy);                        isSlidingToLast = dy > 0; //上拉,下滑                        Log.d(TAG, "dx = " + dx + " dy=" + dy + " isSlidingToLast=" + isSlidingToLast);                    }                }        );    }    private boolean isPullToBottom() {        int[] lastIndexs = mLayoutManager.findLastCompletelyVisibleItemPositions(null);        Log.d(TAG, "last item =" + Arrays.toString(lastIndexs) + ", have item=" + mAdapter.getItemCount());        int maxIndex = mAdapter.getItemCount() - 1;        for (int i : lastIndexs) {            if (i == maxIndex) {                return true;            }        }        return false;    }    private void loadData(boolean isClear) {        if (isClear) {            mItem.clear();        }        previousLastIndex = mItem.size();        Random r = new Random();        for (int index = 0; index < PRE_SCREEN_NUMBER && index < RES_URL.length; index++) {            mItem.add(new Pair("Card " + (previousLastIndex + index), RES_URL[r.nextInt(RES_URL.length)]));        }        Log.d(TAG, "mItem count =" + mItem.size());    }}

    说明:

    RecycleView的ItemView的数据由Pair对象管理存储

    Fresco库默认配置下的使用之前需要初始化调用Fresco.initialize(Context)

    上述实现了2个事件监听,一个OnScrollerListener由RecycleView提供,实现下拉刷新;一个OnRecycleViewItemClickListener由自定义的RecycleViewAdpater提供,实现单击itemView来更换图片(SimpleDraweeView)和文字(TextView)。

    和库的具体使用参见其Github上的文档。

 

5. 效果图

  

  比较遗憾ScreenRecord不支持模拟器和Android4.4一下的系统,只能附上截图。