##RecycleView简单介绍
RecyclerView控件和ListView的原理有非常多相似的地方,都是维护少量的View来进行显示大量的数据。只是RecyclerView控件比ListView更加高级而且更加灵活。当我们的数据由于用户事件或者网络事件发生改变的时候也能非常好的进行显示。和ListView不同的是,RecyclerView不用在负责Item显示相关的功能。全部有关布局、绘制、数据绑定等都被分拆成不同的类进行管理。同一时候RecyclerView控件提供了下面两种方法来进行简化和处理大数量集合:

1.基本使用

RecycleView的基本使用
  1. RecycleView导包(可有可无) dependencies中加入
  2. compile'com.android.support:recyclerview-v7:23.1.1'  
  3. 在布局文件里定义

    <android.support.v7.widget.RecyclerView
        android:
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
    

3.对其进行初始化

 rcv_history = (RecyclerView) findViewById(R.id.rcv_history);

4.LinearLayoutManager 和 GrideLayouManager 两种显示风格

//LinearLayoutManager(ListView)
rcv_history.setLayoutManager(new  (HistoryActivity.this));

//GridLayoutManager(GrideView)

    //第二个參数 就是GridView一样 一行显示个个数
rcv_history.setLayoutManager(new GridLayoutManager(HistoryActivity.this,2));

rcv_history.setAdapter(Adapter);

创建一个类继承RecycleView.Adapter

5.RecycleView.Adapter==> class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.MediaHolder>//指定泛型

创建一个类 集成RecycleView.ViewHolder()

//返回的是一个Holder
 @Override
    //i不是下标 而是类型  怎样实现了getItemViewType()//
    //onCreateViewHolder载入相应布局,初始化相应的holder,每种布局相应自己的holder
    public HistoryAdapter.MediaHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        MediaHolder holder = new   MediaHolder(LayoutInflater.from(HistoryActivity.this).inflate(R.layout.item_history,null));
           View view = null;
            ViewHolder holder = null;
            switch(viewType ){case... break}//依据类型的不同载入相应的布局

        return holder;
    }


    class MediaHolder extends RecycleView.ViewHolder{
            View view;

            public MediaHolder(View itemView) {//构造器  itemView列表中的item,类似convertView
            super(itemView);
            this.view = itemView;//对item布局进行初始化
            //textView = itemView.findViewById(R.id.textView);
            iv_item_history_icon = (ImageView) itemView.findViewById(R.id.iv_item_history_icon);
            tv_item_history_title = (TextView) itemView.findViewById(R.id.tv_item_history_title);
            tv_item_history_duration = (TextView) itemView.findViewById(R.id.tv_item_history_duration);
            iv_item_history_del = (ImageView) itemView.findViewById(R.id.iv_item_history_del);
        }
    }

6.//onBindViewHolder 绑定相应的holder,载入相应的布局
设置Item的显示 //第一个參数 onCreateViewHolder中返回的Holder类型 第二个參数指定的下标
public void onBindViewHolder(HistoryAdapter.MediaHolder holder, final int position) {                   holder.ivitemhistory_icon.setImageResource(); } //返回Item的总大小
@Override public int getItemCount() { if(mediaInfos!=null) {   return mediaInfos.size();
      }else {
         return 0;
   }
}

7.自己定义RecycleView的监听 1.自己定义RecycleView 2.Adapter里设置监听

1. 创建一个接口
    public interface RecycleItemClickListener{
        void onItemClickListener(View view,int position);
    }

2.声明变量
    RecycleItemClickListener listener;
3.set方法
     public void setRecycleItemClickListener(RecycleItemClickListener recycleItemClickListener) {
        this.recycleItemClickListener = recycleItemClickListener;
    }
4.实现的地方
     //在Hodler中 得到itemVidew对象
      //this.view = itemView;在ViewHolder个构造器里获得其View
    在onBindViewHolder下//在此才有position
    public void onBindViewHolder(HistoryAdapter.MediaHolder holder, final int position){
            holder.view.setOnClickListener(new OnClickListener(){
                    public void onClick(View v){
                        if(listener!=null){
                            listener.onItemClickListener(holder.view,position)
                        }
                    }
            });
    }

5.实现监听
    adapter.setRecycleItemClickListener(new RecycleItemClickListener(
            public void onItemClickListener(holder.view,position){
                //对其进行一系列的操作
            }   
    ))

----------------------------------------------------------------------------------------------------------------------------------------------


具体使用

採用LayoutManager来处理Item的布局

提供Item操作的默认动画。比如在添加或者删除item的时候

为了使用RecyclerView控件,我们须要创建一个Adapter和一个LayoutManager:

Adapter:继承自RecyclerView.Adapetr类。主要用来将数据和布局item进行绑定。

LayoutManager:布局管理器。设置每一项view在RecyclerView中的位置布局以及控件item view的显     

示或者隐藏。当View重用或者回收的时候,LayoutManger都会向Adapter来请求新的数据来进行替换原来数据的内容。这样的回收重用的机制能够提供性能,避免创建非常多的view或者是频繁的调用findViewById方法。

这样的机制和ListView还是非常相似的。



RecyclerView提供了三种内置的LayoutManager:

LinearLayoutManager:线性布局,横向或者纵向滑动列表


GridLayoutManager:表格布局


StaggeredGridLayoutManager:流式布局,比如瀑布流效果


长处:插拔式,高度的解耦。异常灵活

#主要API
    LayoutManager:布局管理器(LinearLayoutManager 、GridLayoutManager、StaggeredGridLayoutManager)
    
    ItemDecoration:绘制Item间的间隔
    
    ItemAnimator:Item增删的动画

#使用步骤
1.build.gradle中加入

    dependencies {  
       ……
       
      compile'com.android.support:recyclerview-v7:23.1.1'  
    }

2.布局内加入

    <android.support.v7.widget.RecyclerView  
           android:>           ></android.support.v7.widget.RecyclerView> 

3.代码中初始化并设置

    RecyclerView recycleView = findView(R.id.recyclerview);

设置布局管理器

    LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);//线性
    
    GridLayoutManager gridLayoutManager=new GridLayoutManager(this,4);//网格
    
    StaggeredGridLayoutManager staggeredGridLayoutManager=new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL);//流式

设置布局管理器的方向

        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

设置

    recyclerView.setLayoutManager(layout);

    recyclerView.setAdapter(adapter);
    recyclerView.addItemDecoration(new DividerGridItemDecoration(this));//加入切割线,继承RecyclerView.ItemDecoration
    recyclerView.setItemAnimator(new DefaultItemAnimator());//设置默认Item增删动画

#Adapter的实现

1.自己定义类继承RecycleView的Adapter同一时候绑定ViewHolder

    class MyAdapter extends RecyclerView.Adapter<MyViewHolder>


2.实现方法

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater mInflater = LayoutInflater.from(context);
            MyViewHolder holder = new MyViewHolder(mInflater.inflate(
                R.layout.item_home, parent, false));
            return holder;
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.tv.setText(mDatas.get(position));
        }

        @Override
        public int getItemCount() {
            return mDatas.size();
        }
3.MyViewHolder

    class MyViewHolder extends RecyclerView.ViewHolder {

        TextView tv;

        public MyViewHolder(View view) {
            super(view);
            tv = (TextView) view.findViewById(R.id.id_num);
        }
    }

#增删Item的动画
        mDatas.add(position, "Insert One");
        notifyItemInserted(position);//添加
        mDatas.remove(position);
        notifyItemRemoved(position);//删除

#设置点击监听

1.在Adapter中自己定义监听

    public interface OnItemClickLitener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

2.在onBindViewHolder方法中绑定

        if (mOnItemClickLitener != null) {
            holder.itemView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    removeData(pos);
                    return false;
                }
            });
        }

3.在Activity中设置监听

    mAdapter.setOnItemClickLitener(new HomeAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(HomeActivity.this, position + " click",
                        Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(HomeActivity.this, position + " long click",
                        Toast.LENGTH_SHORT).show();
            }
        });
#分类型的RecycleView
1.MyAdapter继承RecyclerView.Adapter<RecyclerView.ViewHolder>

    class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>

2.通过枚举定义不同的Item

    //枚举Item
    public enum ITEM_TYPE {
        ITEM1,
        ITEM2,
        ITEM3,
        ITEM4
    }

3.依据不同的Item载入不同的ViewHolder

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //载入的时候,依据不同的Item载入不同的布局
        //Enum类提供了一个ordinal()方法。返回枚举类型的序数。这里ITEM_TYPE.ITEM1.ordinal()代表0, ITEM_TYPE.ITEM2.ordinal()代表1
        if (viewType == ITEM_TYPE.ITEM1.ordinal()) {
            return new Item1ViewHolder(layoutInflater.inflate(R.layout.item1, parent, false));
        } else if (viewType == ITEM_TYPE.ITEM2.ordinal()) {
            return new Item2ViewHolder(layoutInflater.inflate(R.layout.item2, parent, false));
        } else if (viewType == ITEM_TYPE.ITEM3.ordinal()) {
            return new Item3ViewHolder(layoutInflater.inflate(R.layout.item3, parent, false));
        } else {
            return new Item4ViewHolder(layoutInflater.inflate(R.layout.item4, parent, false));
        }
    }

4.依据position返回不同类型的Item

    @Override
    public int getItemViewType(int position) {
        
        if (position < item1.size()) {
            return ITEM_TYPE.ITEM1.ordinal();
        } else if (position < item2.size()+item1.size()) {
            return ITEM_TYPE.ITEM2.ordinal();
        } else if (position < item3.size()+item2.size()+item1.size()) {
            return ITEM_TYPE.ITEM3.ordinal();
        } else if (position < item4.size()+item3.size()+item2.size()+item1.size()) {
            return ITEM_TYPE.ITEM4.ordinal();
        }
        return super.getItemViewType(position);
    }

5.依据Item的类型设置数据

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        //依据holder的类型设置数据
        if (holder instanceof Item1ViewHolder) {

            if(position<item1.size()){
                ((Item1ViewHolder) holder).tv1.setText(item1.get(position));
            }
            
        }else if(holder instanceof Item1ViewHolder){

            if(position>item1.size()&&position<item1.size()+item2.size()){
                ((Item2ViewHolder) holder).tv2.setText(item2.get(position));
            }
            
        }else{
            ......
        }
    }
6.返回总数量
    
    @Override
    public int getItemCount() {
        return item1.size() + item2.size() + item3.size() + item4.size();
    }

7.创建ViewHolder

    public static class Item1ViewHolder extends RecyclerView.ViewHolder {

        TextView tv;

        public Item1ViewHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.tv);
        }
    }

    public static class Item2ViewHolder extends RecyclerView.ViewHolder {

        TextView tv;

        public Item2ViewHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.tv);
        }
    }

    public static class Item3ViewHolder extends RecyclerView.ViewHolder {

        TextView tv;

        public Item3ViewHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.tv);
        }
    }

    public static class Item4ViewHolder extends RecyclerView.ViewHolder {

        TextView tv;

        public Item4ViewHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.tv);
        }
    }

    ......


------------------------------------------------------------------------------------------------------------------------------------------------


通用adapter

參考自:http://blog.csdn.net/lmj623565791/article/details/47251585; 本文出自:【张鸿洋的博客】

一、概述

记得好久曾经针对ListView类控件写过一篇打造万能的ListView GridView 适配器。现在RecyclerView异军突起,其Adapter的使用方法也与ListView类似。那么我们也能够一步一步的为其打造通用的Adapter,使下列使用方法书写更加简单:

  • 简单的数据绑定(单种Item)
  • 多种Item Type 数据绑定
  • 添加onItemClickListener , onItenLongClickListener
  • 优雅的加入分类header

二、使用方式和效果图

在一步一步完毕前。我们先看下使用方式和效果图:

(1)简单的数据绑定

首先看我们最经常使用的单种Item的书写方式:

是不是相当方便,在convert方法中完毕数据、事件绑定就可以。

(2)多种ItemViewType

多种ItemViewType,正常考虑下。我们须要依据Item指定ItemType。而且依据ItemType指定对应的布局文件。我们通过MultiItemTypeSupport完毕指定:

剩下就简单了,将其作为參数传入到MultiItemCommonAdapter就可以。

贴个效果图:

为RecyclerView打造通用Adapter

(3)加入分类header

事实上属于多种ItemViewType的一种了,仅仅是比較经常使用。我们就简单封装下。

依赖正常考虑下。这样的方式须要额外指定header的布局。以及布局中显示标题的TextView了。以及依据Item显示什么样的标题。

我们通过SectionSupport对象指定:

3个方法。一个指定header的布局文件,一个指定布局文件里显示title的TextView。最后一个用于指定显示什么样的标题(依据Adapter的Bean)。

接下来就非常easy了:

这样就完了。效果图例如以下:

为RecyclerView打造通用Adapter

ok,看完上面简单的介绍,相信你已经基本了解了,没错,和我上篇ListView万能Adapter的使用方式基本一样,而且已经封装到同一个库了,链接为:https://github.com/hongyangAndroid/base-adapter。此外还提供了ItemClick,ItemLongClick,加入EmptyView等支持。

说了这么多。以下进入正题。看我们怎样一步步完毕整个封装的过程。

三、通用的ViewHolder

RecyclerView要求必须使用ViewHolder模式,一般我们在使用过程中,都须要去建立一个新的ViewHolder然后作为泛型传入Adapter。那么想要建立通用的Adapter。必须有个通用的ViewHolder。

首先我们确定下ViewHolder的基本的作用,实际上是通过成员变量存储相应的convertView中须要操作的字View,避免每次findViewById。从而提升执行的效率。

那么既然是通用的View。那么对于不同的ItemType肯定没有办法确定创建哪些成员变量View。取而代之的仅仅能是个集合来存储了。

那么代码例如以下:

代码非常easy,我们的ViewHolder继承自RecyclerView.ViewHolder,内部通过SparseArray来缓存我们itemView内部的子View。从而得到一个通用的ViewHolder。每次须要创建ViewHolder仅仅须要传入我们的layoutId就可以。

ok,有了通用的ViewHolder之后,我们的通用的Adapter分分钟就出来了。

四、通用的Adapter

我们的每次使用过程中。针对的数据类型Bean肯定是不同的,那么这里肯定要引入泛型代表我们的Bean,内部通过一个List代表我们的数据,ok,剩下的看代码:

继承自RecyclerView.Adapter,须要复写的方法还是比較少的。首先我们使用过程中传输我们的数据集mDatas,和我们item的布局文件layoutId。

onCreateViewHolder时,通过layoutId就可以利用我们的通用的ViewHolder生成实例。

onBindViewHolder这里主要用于数据、事件绑定,我们这里直接抽象出去。让用户去操作。能够看到我们改动了下參数,用户能够拿到当前Item所须要的对象和viewHolder去操作。

那么如今用户的使用是这种:

看到这里,爽了非常多,眼下我们只写了非常少的代码,可是我们的通用的Adapter感觉已经初步完毕了。

能够看到我们这里通过viewholder依据控件的id拿到控件,然后再进行数据绑定和事件操作,我们还能做些什么简化呢?

恩。我们能够通过一些辅助方法简化我们的代码,所以继续往下看。

五、进一步封装ViewHolder

我们的Item实际上使用的控件较多时候可能都是TextView,ImageView等,我们一般在convert方法都是去设置文本,图片什么的,那么我们能够在ViewHolder里面,写上例如以下的一些辅助方法:

当然上面仅仅给出了几个方法。你能够把经常使用控件的方法都写进去。而且在使用过程中不断完好就可以。

有了一堆辅助方法后,我们的操作更加简化了一步。

ok,到这里,我们的针对单种ViewItemType的通用Adapter就完毕了。代码非常easy也非常少。可是简化效果非常明显。

ok,接下来我们考虑多种ItemViewType的情况。

六、多种ItemViewType

多种ItemViewType,一般我们的写法是:

  • 复写getItemViewType,依据我们的bean去返回不同的类型
  • onCreateViewHolder中依据itemView去生成不同的ViewHolder

假设大家还记得,我们的ViewHolder是通用的,唯一依赖的就是个layoutId。那么上述第二条就变成,依据不同的itemView告诉我用哪个layoutId就可以。生成viewholder这样的事我们通用adapter来做。

于是,引入一个接口:

能够非常清楚的看到,这个接口实际就是完毕我们上述的两条工作。用户在使用过程中。通过实现上面两个方法,指明不同的Bean返回什么itemViewType,不同的itemView所相应的layoutId.

ok,有了上面这个接口,我们的參数就够了,以下開始我们的MultiItemCommonAdapter的编写。

差点儿没有几行代码,感觉简直不须要消耗脑细胞。getItemViewType用户的传入的MultiItemTypeSupport.getItemViewType完毕。onCreateViewHolder中依据MultiItemTypeSupport.getLayoutId返回的layoutId,去生成ViewHolder就可以。

ok,这种话,我们的多种ItemViewType的支持也就完毕了,一路下来感觉还是蛮轻松的~~~

最后。我们还有个加入分类的header,为什么想起来封装这个呢,这个是由于我看到了这么个项目:https://github.com/ragunathjawahar/simple-section-adapter。这个项目给了种类似装饰者模式的方法。为ListView加入了header,有兴趣能够看下。

我想我们的RecylerView也来个吧。只是我们这里直接通过继承Adapter完毕。

七、加入分类Header

话说加入分类header。事实上就是我们多种ItemViewType的一种,那么我们须要知道哪些參数呢?

简单思考下。我们须要:

  1. header所相应的布局文件
  2. 显示header的title相应的TextView
  3. 显示的title是什么(一般肯定依据Bean生成)

ok,这种话。我们依旧引入一个接口,用于提供上述3各參数

方法名应该非常明白了,这里引入泛型,相应我们使用时的数据类型Bean。

刚才也说了我们的分类header是多种ItemViewType的一种,那么直接继承MultiItemCommonAdapter实现。

依据我们之前的代码。使用MultiItemCommonAdapter,须要提供一个MultiItemTypeSupport。我们这里当然也不例外。能够看到上述代码,我们初始化了成员变量headerItemTypeSupport,分别对getLayoutIdgetItemViewType进行了实现。

  • getLayoutId假设type是header类型,则返回mSectionSupport.sectionHeaderLayoutId();否则则返回mLayout.
  • getItemViewType依据位置推断,假设当前是header所在位置,返回header类型常量。否则返回1.

ok,能够看到我们构造方法中调用了findSections(),主要为了存储我们的title和相应的position,通过一个MapmSections来存储。

那么相应的getItemCount()方法,我们多了几个title肯定总数会添加。所以须要复写。

onBindViewHolder中我们有一行重置position的代码,由于我们的position变大了,所以在实际上绑定我们数据时,这个position须要还原,代码逻辑见getIndexForPosition(position)

最后一点就是,每当我们的数据发生变化,我们的title集合,即mSections就可能会发生变化。所以须要又一次生成,本来准备复写notifyDataSetChanged方法。在里面又一次生成,没想到这种方法是final的。于是利用了registerAdapterDataObserver(observer);,在数据发生变化回调中又一次生成,记得在onDetachedFromRecyclerView里面对注冊的observer进行解注冊。

ok,到此我们的添加Header就结束了~~

恩,上面是针对普通的Item添加header的代码,假设是针对多种ItemViewType呢?事实上也非常easy,这样的方式须要传入MultiItemTypeSupport

那么对于headerItemTypeSupport中的getItemViewType等方法,不是header类型时。交给传入的MultiItemTypeSupport就可以。大致的代码例如以下:

那么这种话,今天的博客就结束了,有几点须要说明下:

本来是想接着曾经的万能Adapter后面写。可是为了本文的独立和完整性。还是尽可能没有去依赖上篇博客的内容了。

此外,文章最后给出的开源代码与上述代码存在些许的差异。由于开源部分源代码整合了ListView,RecyclerView等,而本文上述代码全然针对RecyclerView进行编写。

对于ItemClick,ItemLongClick的代码就不赘述了,事实上都是通过itemView.setXXXListener完毕,具体的參考代码就可以。

很多其它具体的内容以及代码,參见https://github.com/hongyangAndroid/base-adapter

相关文章:

  • 2021-09-21
  • 2021-10-24
  • 2021-09-20
  • 2021-07-21
  • 2021-07-18
  • 2021-07-08
  • 2021-11-19
  • 2021-06-11
猜你喜欢
  • 2021-10-23
  • 2021-06-19
  • 2022-12-23
  • 2021-04-08
  • 2022-01-03
  • 2022-12-23
相关资源
相似解决方案