Android中RecyclerView(可以设置瀑布流)

RecyclerView可以做1,listview 2,GridView 3, StaggeredGridLayout(瀑布流布局)
添加依赖可以去谷歌库上查找

    compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'

Mainactivity

package com.example.administrator.recyclerview_text;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private RecyclerView Recyclerview;
    ArrayList   mIntegerArrayList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Recyclerview = (RecyclerView) findViewById(R.id.Recyclerview);
        mIntegerArrayList=new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            if(i % 2 == 0){
                mIntegerArrayList.add(R.drawable.q);
            }else{
                mIntegerArrayList.add(R.drawable.q1);
            }
        }

        //创建设置排列方式的布局管理器对象   线性布局、网格布格、瀑布流布局
        //线性布局
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //对于线性布局管理器  需要设置其显示的排列方向
        linearLayoutManager.setOrientation(OrientationHelper.VERTICAL);

        //设置网格布局
        GridLayoutManager grid = new GridLayoutManager(MainActivity.this,2);

        //设置瀑布流布局(参数1,设置行数或列数看后面那个方向,参数2,是设置垂直)
        StaggeredGridLayoutManager staggeredGridLayout =
                new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);

        //将布局管理器设置给RecyclerView
        Recyclerview.setLayoutManager(staggeredGridLayout);
        //设置显示动画(添加、删除)
        Recyclerview.setItemAnimator(new DefaultItemAnimator());
        //设置适配器
         MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(mIntegerArrayList,MainActivity.this);
        Recyclerview.setAdapter(adapter);
    }
}

mainactivity布局




    

    




MyRecyclerViewAdapter适配器

package com.example.administrator.recyclerview_text;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import java.util.ArrayList;

/**
 * Created by Administrator on 2018/8/6 0006.
 */

public class MyRecyclerViewAdapter extends RecyclerView.Adapter {
    ArrayList mIntegerArrayList;
    Context mContext;
    public MyRecyclerViewAdapter(ArrayList mIntegerArrayList, Context mContext) {
this.mIntegerArrayList=mIntegerArrayList;
        this.mContext=mContext;
    }

    @Override //创建ViewHolder对象 完成视图的绑定
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = View.inflate(mContext,R.layout.item,null);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        holder.wo.setImageResource(mIntegerArrayList.get(position));

        holder.wo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
             delete(position);
            }
        });
    }

    @Override
    public int getItemCount() {
        return mIntegerArrayList.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder{
        private ImageView wo;


        public MyViewHolder(View itemView) {
            super(itemView);
            wo = (ImageView) itemView.findViewById(R.id.wo);

        }
    }
    //自定义添加  动画效果
    public void add(int position){
        mIntegerArrayList.add(position,R.mipmap.ic_launcher);
        notifyItemInserted(position);
        notifyItemRangeChanged(position, mIntegerArrayList.size());

    }
    //自定义删除  动画效果
    public void delete(int position){
        mIntegerArrayList.remove(position);
        notifyItemRemoved(position);
        notifyItemRangeChanged(position, mIntegerArrayList.size());

    }

    public void updateAdapter(ArrayList alist){
        this.mIntegerArrayList = alist;
        notifyDataSetChanged();

    }
}

item





效果图

Android中RecyclerView(可以设置瀑布流)_第1张图片
image.png

pulltorefresh 实现瀑布流的方式(基于recycleview)
https://blog.csdn.net/qq_35534596/article/details/78466292?locationNum=5&fps=1
RecyclerView的上拉刷新下拉加载
https://blog.csdn.net/a1533588867/article/details/54949058
详细

一.RecyclerView是什么?
    自Android 5.0之后,谷歌公司推出了RecylerView控件,RecylerView,我想看到一个新名词后大部分人会首先发出一个疑问,recylerview是什么?
    RecylerView是support-v7包中的新组件,是一个强大的滑动组件,用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、GridView。
二.RecyclerView的优点是什么?
    根据官方的介绍RecylerView是ListView的升级版,既然如此那RecylerView必然有它的优点,现就RecylerView相对于ListView的优点罗列如下:
    ①RecylerView封装了viewholder的回收复用,也就是说RecylerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单。
    ②提供了一种插拔式的体验,高度的解耦,异常的灵活,针对一个Item的显示RecylerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。

一.使用RecyclerView环境配置
    RecyclerView是Android系统提供的新控件,自然按照谷歌的一贯作风,我们需要下载一个支持库。android.support.v7。所以使用该控件,我们需要添加v7包的引用。v7下载地址:
        http://download.csdn.net/detail/mr_dsw/9146755
    下载完成后,我们需要在开发环境中添加该包的引用。简要介绍在Eclipse和Android Studio中的引用方式。
        1.Eclipse添加V7包
    1)在eclipse的工作控件将v7包导入到我们的工程中。注意:此时应将我们下载好的v7包放到我们工程目录下,不然后面导入后会出问题。
    2)选中我们的项目,右键properties属性,进入如下图,我们点击add,系统就会在我们的工作目录下,找到Library类库,供我们添加,我们选择v7即可。这样我们就可以使用RecyclerView了。

    2.AndroidStudio中添加v7包
    1)要确保已经将Android Support Libraries升级到最新。 
    2)打开我们的module对应的build.gradle文件,在dependencies中添加:
    compile 'com.android.support:recyclerview-v7:23.4.0'
    3)重新Build一下工程即可。
二.相关类介绍
  1.RecyclerView
    我们打开源码,看到
        public class RecyclerView extends ViewGroup
    所以这也就是我们常见的自定义ViewGroup,只不过这个玩意比较牛逼罢了。通过源码,我们看到这玩意有很多方法,但是我们仅仅挑选几个常用的来说说。
    1)public void setAdapter(Adapter adapter)
    根据我们使用的经验,显然这个方法是让我们绑定数据的,只不过这个Adapter是:
    public static abstract class Adapter
类型的。
    2)public void setLayoutManager(LayoutManager layout)
    看到layout开头,显然是跟布局有关,又有manager,所以这个LayoutManager肯定就是负责RecyclerView的布局的类。


    3)public void addItemDecoration(ItemDecoration decor, int index)
    为每个item附加的子视图,这个方法可用于添加分割线,这点和我们使用ListView的setDivider()有点类似,此时,我们只要传入一个ItemDecoration对象。
    4)public void setItemAnimator(ItemAnimator animator)
    这个方法很牛逼,可以设置动画。先来看看官方文档对此方法的注释。
/* 
 * Sets the {@link ItemAnimator} that will handle animations involving changes
 * to the items in this RecyclerView. By default, RecyclerView instantiates and
 * uses an instance of {@link DefaultItemAnimator}. Whether item animations are
 * enabled for the RecyclerView depends on the ItemAnimator and whether
 * the LayoutManager {@link LayoutManager#supportsPredictiveItemAnimations()
 * supports item animations}.
 */
    前面注释的大概意思就是通过此方法设置ItemAnimator对象来实现RecyclerView的item的动画,默认情况下,使用DefaultItemAnimator动画。动画是否有效取决于ItemAnimator和LayoutManager的类对象。
    以上就是众多方法中比较常用的四个,这四个方法的灵活性很高,所以也铸就了RecyclerView的高度灵活性,看了上面的四个方法,我们可以肯定RecyclerView类的内部肯定有对应的四个类对象来处理所需的效果。

  2.LayoutManager
    上面也分析了,这个LayoutManager就是我们的布局管理器。我们下来看看一张类的组织结构图。









    我们先来看看该类的定义源码来一睹风采。
        public static abstract class LayoutManager
    
    通过源码,看到这个类原来是一个抽象类,那我们setLayoutManager(LayoutManager layout)时难道要我们自定义一个LayoutManager对象么?不会的,如果真是那样,我估计RecyclerView就变的极其复杂了,为什么?且看源码对该类的注释。
/**
     * A LayoutManager is responsible for measuring and positioning item views
     * within a RecyclerView as well as determining the policy for when to recycle
     * item views that are no longer visible to the user. By changing the LayoutManager
     * a RecyclerView can be used to implement a standard vertically scrolling list,
     * a uniform grid, staggered grids, horizontally scrolling collections and more. Several stock
     * layout managers are provided for general use.
 */
    意思就是:LayoutManager负责RecyclerView中item的测量以及放置,同时也管理着item的回收。通过改变LayoutManager可以让RecyclerView形成垂直滚动的效果(ListView),统一网格效果(GridView)、交错网格效果(瀑布流)、横向滚动效果(HorizontalListView)等等。
    所以说,这么复杂的东西怎么能让开发者完全实现呢?安卓肯定会给我们提供几个实现好的类。
    LinearLayoutManager:线性布局管理器,支持横向和纵向形式。
    GridLayoutManager: 网格布局管理器。
    StaggeredGridLayoutManager:瀑布流式布局管理器
    所以在实际开发中,我们可以根据实际需要进行使用,一般情况下,这三个子类能完全满足我们的需求,更高需求,请自定义LayoutManager对象。
  3.ItemDecoration
    为每个item附加的子视图,这个类可用于我们设置分割线,同样也是RecyclerView类的内部类,那么我们看看它的定义形式:
        public static abstract class ItemDecoration
    又是一个抽象类,所以注定了它是不平凡的,即我们需要自定义它的子类来实现绚丽的分割效果,官方现在好像还没有吧!以后估计可能有。
  4.ItemAnimator
    一看,跟Animator沾边,八成就是搞动画的出身。同样该类也是RecyclerView类的内部类,我们看看它的定义吧!
        public static abstract class ItemAnimator
        所以注定了不平凡有不平凡的伟大,我们需要自定义子类来实现动画,系统也提供默认的。

    关于RecyclerView的基本要素,我们简要说了下,总体来说,功能很强大,能玩多6全看自身水平多高,涉及的方面比较多,上手比较容易,想精通这个控件,还是需要下很大功夫的。下面就开始学习使用这个控件了。
三.RecyclerView的初步用法(包括RecyclerView.Adapter用法)
    基本使用步骤:
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);  
LinearLayoutManager layoutManager = new LinearLayoutManager(this );  
//设置布局管理器  
recyclerView.setLayoutManager(layoutManager);  
//设置为垂直布局,这也是默认的  
layoutManager.setOrientation(OrientationHelper. VERTICAL);  
//设置Adapter  
recyclerView.setAdapter( recycleAdapter);  
 //设置分隔线  
recyclerView.addItemDecoration( new DividerGridItemDecoration(this ));  
//设置增加或删除条目的动画  
recyclerView.setItemAnimator( new DefaultItemAnimator());
    可以看到对RecylerView的设置过程,比ListView要复杂一些,这也是RecylerView高度解耦的表现,虽然代码抒写上有点复杂,但它的扩展性是极高的。
    在了解了RecyclerView的一些控制之后,紧接着来看看它的Adapter的写法,RecyclerView的Adapter与ListView的Adapter还是有点区别的,RecyclerView.Adapter,需要实现3个方法:
    ①onCreateViewHolder()
    这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,当然这个ViewHolder需要我们自己去编写。直接省去了当初的convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
    
    ②onBindViewHolder()
    这个方法主要用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView。
    ③getItemCount()
    这个方法就类似于BaseAdapter的getCount方法了,即总共有多少个条目。

    实例:接着来几个小的实例帮助大家更深入的了解RecyclerView的用法,首先来实现一个最简单的列表,效果如下图:
    这种效果的MainAcitivity的代码如下:
public class MainActivity extends ActionBarActivity {  
     private RecyclerView recyclerView;  
     private List mDatas;  
     private MyRecyclerAdapter recycleAdapter;  
     @SuppressLint("NewApi") @Override  
     protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout. activity_main);  
            recyclerView = (RecyclerView) findViewById(R.id.recyclerView );  
            initData();  
            recycleAdapter= new MyRecyclerAdapter(MainActivity.this , mDatas );  
            LinearLayoutManager layoutManager = new LinearLayoutManager(this);  
            //设置布局管理器  
            recyclerView.setLayoutManager(layoutManager);  
            //设置为垂直布局,这也是默认的  
            layoutManager.setOrientation(OrientationHelper.VERTICAL);  
            
            //设置Adapter  
            recyclerView.setAdapter( recycleAdapter);  
            //设置增加或删除条目的动画  
            recyclerView.setItemAnimator(new DefaultItemAnimator());  
             
     }  
  
     private void initData() {  
            mDatas = new ArrayList();  
            for ( int i=0; i < 40; i++) {  
                 mDatas.add( "item"+i);  
           }  
     }  
}
    RecyclerView的Adapter的代码如下:
public class MyRecyclerAdapter extends 
RecyclerView.Adapter {  
       
     private List mDatas;  
     private Context mContext;  
     private LayoutInflater inflater;  
       
     public MyRecyclerAdapter(Context context, List datas){  
            this. mContext=context;  
            this. mDatas=datas;  
            inflater=LayoutInflater. from(mContext);  
     }  
       
     @Override  
     public int getItemCount() {  
             
            return mDatas.size();  
     }  
  
     
//填充onCreateViewHolder方法返回的holder中的控件  
@Override  
public void onBindViewHolder(MyViewHolder holder, final int position) {
     holder.tv.setText( mDatas.get(position));  
} 
//重写onCreateViewHolder方法,返回一个自定义的ViewHolder  
@Override  
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
     View view = inflater.inflate(R.layout. item_home,parent, false);  
     MyViewHolder holder= new MyViewHolder(view);  
     return holder;  
}  
class MyViewHolder extends ViewHolder{  
     TextView tv;
     public MyViewHolder(View view) {  
           super(view);  
           tv=(TextView) view.findViewById(R.id. tv_item);  
     }  
}  
}
    可以看到RecyclerView标准化了ViewHolder,编写 Adapter面向的是ViewHoder而不在是View了,复用的逻辑被封装了,写起来更加简单。其实它的写法与BaseAdapter的写法是差不多的,大家可以对比下它与getView方法写法的区别,在onCreateViewHolder方法中初始化了一个View,然后返回一个ViewHolder,这个返回的ViewHolder类似于之前在getView中的convertView.getTag(),然后在onBindViewHolder方法中去给这个ViewHolder中的控件填充值。其实它的原理跟getView是差不多的,只是做了封装,我们写起来比较简洁。到这里,看到上述运行效果可能有很多人会说,这效果太丑了,连个分隔线都没有,不要急,我们一步一步来。
四.RecyclerView增加分隔线
    前面我们说到可以通过
    RecyclerView.addItemDecoration(ItemDecoration decoration)
    这个方法进行设置,其中它需要的参数就是我们自己定义的继承自ItemDecoration的一个对象。我们可以创建一个继承RecyclerView.ItemDecoration类来绘制分隔线,通过ItemDecoration可以让我们每一个Item从视觉上面相互分开来,例如ListView的divider非常相似的效果。当然像我们上面的例子ItemDecoration我们没有设置也没有报错,那说明ItemDecoration我们并不是强制需要使用,作为我们开发者可以设置或者不设置Decoration的。实现一个ItemDecoration,系统提供的ItemDecoration是一个抽象类,内部除去已经废弃的方法以外,我们主要实现以下三个方法:
public static abstract class ItemDecoration {   
      public void onDraw(Canvas c,RecyclerView parent,State state) {   
          onDraw(c,parent);   
      }   
      public void onDrawOver(Canvas c,RecyclerView parent,State state) {   
          onDrawOver(c,parent);   
      }   
      public void getItemOffsets(RectoutRect, View view,RecyclerView parent,State state) {   
          getItemOffsets(outRect,((LayoutParams)view.getLayoutParams())
          .getViewLayoutPosition(),parent);   
      }   
  }
    又因为当我们RecyclerView在进行绘制的时候会进行绘制Decoration,那么会去调用onDraw和onDrawOver方法,那么这边我们其实只要去重写onDraw和getItemOffsets这两个方法就可以实现啦。然后LayoutManager会进行Item布局的时候,会去调用getItemOffset方法来计算每个Item的Decoration合适的尺寸,下面我们来具体实现一个Decoration,DividerItemDecoration.Java:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {  
  
    private static final int[] ATTRS = new int[]{  
            android.R.attr. listDivider  
    };  
  
    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;  
    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;  
  
    
    private Drawable mDivider;  
  
    private int mOrientation;  
  
    public DividerItemDecoration(Context context, int orientation) {  
        final TypedArray a = context.obtainStyledAttributes(ATTRS );  
        mDivider = a.getDrawable(0);  
        a.recycle();  
        setOrientation(orientation);  
    }  
  
    public void setOrientation( int orientation) {  
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {  
            throw new IllegalArgumentException( "invalid orientation");  
        }  
        mOrientation = orientation;  
    }  
  
    @Override  
    public void onDraw(Canvas c, RecyclerView parent) {  
        if (mOrientation == VERTICAL_LIST) {  
            drawVertical(c, parent);  
        } else {  
            drawHorizontal(c, parent);  
        }  
    }  
    public void drawVertical(Canvas c, RecyclerView parent) {  
        final int left = parent.getPaddingLeft();  
        final int right = parent.getWidth() - parent.getPaddingRight();  
        final int childCount = parent.getChildCount();  
        for (int i = 0; i < childCount; i++) {  
            final View child = parent.getChildAt(i);  
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child  
                    .getLayoutParams();  
            final int top = child.getBottom() + params.bottomMargin;  
            
            final int bottom = top + mDivider.getIntrinsicHeight();  
            mDivider.setBounds(left, top, right, bottom);  
            mDivider.draw(c);  
        }  
    }  
    public void drawHorizontal(Canvas c, RecyclerView parent) {  
        final int top = parent.getPaddingTop();  
        final int bottom = parent.getHeight() - parent.getPaddingBottom();  
        final int childCount = parent.getChildCount();  
        for (int i = 0; i < childCount; i++) {  
            final View child = parent.getChildAt(i);  
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child  
                    .getLayoutParams();  
            final int left = child.getRight() + params.rightMargin;  
            final int right = left + mDivider.getIntrinsicHeight();  
            mDivider.setBounds(left, top, right, bottom);  
            mDivider.draw(c);  
        }  
    }  
  
    @Override  
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {  
        if (mOrientation == VERTICAL_LIST) {  
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());  
        }else{  
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);  
        }  
    }  
}
    在这里我们采用系统主题(android.R.attr.listDivider)来设置成分隔线的,然后来获取尺寸,位置进行setBound(),绘制,接着通过outRect.set()来设置绘制整个区域范围,当然了它是有两种情况的一种LinearLayoutManager.HORIZONTAL另外一种LinearLayoutManager.VERTICAL需要分别对其进行处理,最后不要忘记
往RecyclerView中设置该自定义的分割线,然后在MainActivity中加上一句:
    recyclerView .addItemDecoration(new DividerItemDecoration(MainActivity.this,
      LinearLayoutManager.VERTICAL))
    即给RecyclerView增加分隔线。
    可以看到已经有了分隔线,跟ListView的效果基本一致了。当然了,既然谷歌给我们提供了这个专门添加分隔线的方法,那它肯定会允许我们自定义分隔线的样式,不然把这个方法抽取出来也没有任何意义。
    
    然后运行,效果如下:
五.改变分隔线样式
    那么怎么更改分隔线的样式呢?在上面的DividerItemDecoration这个类中可以看到这个分隔线是跟ListView一样的,即系统的默认的样式,因此我们可以在styles的xml文件中进行更改,更改如下:
      
    
    divider的内容如下:
      
      
     
            
            
       
            
            
     
    可以看到分隔线的颜色变了,当然了这只是一个小例子,我们可以按照业务需求去更改,这样就基本实现了ListView的效果,看到这肯定会有人说,好麻烦,还不如ListView简单呢,从上面的代码量看来确实是使用起来很复杂,但是如果此时你想将这个列表以GridView的形式展示出来,用RecylerView仅仅是换一行代码的事情,
    在上面的代码中我们使用了:
LinearLayoutManager layoutManager = new LinearLayoutManager(this);  
 //设置布局管理器  
recyclerView.setLayoutManager(layoutManager);
    RecyclerView.LayoutManager是一个抽象类,系统为我们提供了三个实现类:
    ①LinearLayoutManager即线性布局,这个是在上面的例子中我们用到的布局
    ②GridLayoutManager即表格布局
    ③StaggeredGridLayoutManager即流式布局,如瀑布流效果
    假如将上述例子换成GridView的效果,那么相应的代码应该这样改:
        recyclerView .setLayoutManager(new GridLayoutManager( this,4));
    除此之外上述的分隔线也要做相应的更改,因为在上述DividerItemDecoration这个方法中从:
        final int left = parent.getPaddingLeft();  
        final int right = parent.getWidth() - parent.getPaddingRight();
    这两行我们可以看出来,它是绘制了一条线这条线就是从RecyclerView去掉左右边距后,剩余的部分,因为当显示成ListView时每一行就一个Item所以整体效果看上去就跟ListView差不多,而当展示成GridView那样的效果时,每一行就不止一个条目了,而有可能是多个,所以这个类就不再适用了,我们需要重新写一个,代码如下:
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration  
{  
  
     private static final int[] ATTRS = new int[] { android.R.attr.listDivider };  
     private Drawable mDivider;  
  
     public DividerGridItemDecoration(Context context)  
     {  
            final TypedArray a = context.obtainStyledAttributes(ATTRS );  
            mDivider = a.getDrawable(0);  
           a.recycle();  
     }  
     @Override  
     public void onDraw(Canvas c, RecyclerView parent, State state)  
     {  
  
           drawHorizontal(c, parent);  
           drawVertical(c, parent);  
  
     }  
  
     
     
     private int getSpanCount(RecyclerView parent)  
     {  
            // 列数  
            int spanCount = -1;  
           LayoutManager layoutManager = parent.getLayoutManager(); 
          if (layoutManager instanceof GridLayoutManager)  
           {  
  
                spanCount = ((GridLayoutManager) layoutManager).getSpanCount();  
           } else if (layoutManager instanceof StaggeredGridLayoutManager)  
           {  
                spanCount = ((StaggeredGridLayoutManager) layoutManager)  
                           .getSpanCount();  
           }  
            return spanCount;  
     }
     public void drawHorizontal(Canvas c, RecyclerView parent)  
     {  
            int childCount = parent.getChildCount();  
            for ( int i = 0; i < childCount; i++)  
           {  
                 final View child = parent.getChildAt(i);  
                 
            
                 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 
                 child.getLayoutParams();  
                 final int left = child.getLeft() - params.leftMargin;  
                 final int right = child.getRight() + params.rightMargin  
                           + mDivider.getIntrinsicWidth();  
                 final int top = child.getBottom() + params.bottomMargin;  
                 final int bottom = top + mDivider.getIntrinsicHeight();
                 mDivider.setBounds(left, top, right, bottom);  
                 mDivider.draw(c);  
           }  
     }  
     public void drawVertical(Canvas c, RecyclerView parent)  
     {  
            final int childCount = parent.getChildCount();  
            for ( int i = 0; i < childCount; i++)  
           {  
                 final View child = parent.getChildAt(i);  
  
                 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
                 child.getLayoutParams();  
                 final int top = child.getTop() - params.topMargin;
     
                 final int bottom = child.getBottom() + params.bottomMargin;  
                 final int left = child.getRight() + params.rightMargin;  
                 final int right = left + mDivider.getIntrinsicWidth();  
                 mDivider.setBounds(left, top, right, bottom);  
                 mDivider.draw(c);  
           }  
     }  
     private boolean isLastColum(RecyclerView parent, int pos, int spanCount,  
                 int childCount)  
     {  
           LayoutManager layoutManager = parent.getLayoutManager();
           if (layoutManager instanceof GridLayoutManager)  
           {  
                 if ((pos + 1) % spanCount == 0) // 如果是最后一列,则不需要绘制右边  
                {  
                      return true;  
                }  
           } else if (layoutManager instanceof StaggeredGridLayoutManager)  
           {  
                 int orientation = ((StaggeredGridLayoutManager) layoutManager)  
                           .getOrientation();  
                 if (orientation == StaggeredGridLayoutManager.VERTICAL )  
                {  
                   
                 
                     if ((pos + 1) % spanCount == 0) // 如果是最后一列,则不需要绘制右边  
                     {  
                            return true;  
                     }  
                } else  
                {  
                     childCount = childCount - childCount % spanCount;  
                      if (pos >= childCount) // 如果是最后一列,则不需要绘制右边  
                            return true;  
                }  
           }  
            return false;  
     }
     private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,  
                 int childCount)  
     {  
           LayoutManager layoutManager = parent.getLayoutManager();  
            if (layoutManager instanceof GridLayoutManager)  
           {  
                 childCount = childCount - childCount % spanCount;  
                 if (pos >= childCount) // 如果是最后一行,则不需要绘制底部  
            return true;  
           } else if (layoutManager instanceof StaggeredGridLayoutManager)
     
           {  
            int orientation = ((StaggeredGridLayoutManager)
                layoutManager).getOrientation();  
                 // StaggeredGridLayoutManager 且纵向滚动  
                 if (orientation == StaggeredGridLayoutManager.VERTICAL )  
                {  
                     childCount = childCount - childCount % spanCount;  
                      // 如果是最后一行,则不需要绘制底部  
                      if (pos >= childCount)  
                            return true;  
                } else  
                 // StaggeredGridLayoutManager 且横向滚动  
                {
                     // 如果是最后一行,则不需要绘制底部  
                      if ((pos + 1) % spanCount == 0)  
                     {  
                            return true;  
                     }  
                }  
           }  
            return false;  
     }         
     @Override  
     public void getItemOffsets(Rect outRect, int itemPosition,  
                RecyclerView parent)  
     {  
            int spanCount = getSpanCount(parent);  
            int childCount = parent.getAdapter().getItemCount();
            // 如果是最后一行,则不需要绘制底部
            if (isLastRaw(parent, itemPosition, spanCount, childCount))  
           {  
                outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);  
                    // 如果是最后一列,则不需要绘制右边
           } else if (isLastColum(parent, itemPosition, spanCount, childCount))  
           {  
                outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());  
           } else  
           {  
                outRect.set(0, 0, mDivider.getIntrinsicWidth(),  
                            mDivider.getIntrinsicHeight());  
           }  
     }  
}  
            
    别忘了更改分隔线
        recyclerView .addItemDecoration(new DividerGridItemDecoration(this ));
之后运行发现效果如下:(纵向滑动)
    可以看到如果你准备好了分隔线的这个类,从ListView效果到GridView效果,只需要几行代码,是不是瞬间感觉高大上了?还有更让人瞠目结舌的效果,将上述代码做如下更改:
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager
        (4,StaggeredGridLayoutManager.HORIZONTAL);  
        //设置布局管理器  
        recyclerView.setLayoutManager(layoutManager);
    这里需要注意的是StaggeredGridLayoutManager构造的第二个参数传一个orientation,
    如果传入的是:
        StaggeredGridLayoutManager.VERTICAL
那么前面那个参数就代表有多少列;
    如果传入的是:
        StaggeredGridLayoutManager.HORIZONTAL
那么前面那个参数就代表有多少行;
    
    运行效果如下:(横向滑动)
    










    这效果是不是有点逆天?可以看到,固定为4行,变成了左右滑动。有一点需要注意,如果是横向的时候,item的宽度需要注意去设置,毕竟横向的宽度没有约束了,因为控件可以横向滚动了,另外它还可以实现瀑布流的效果,关于瀑布流我准备后面专门写一篇博客。
六.RecyclerView增加和删除的动画(包括RecyclerView.Adapter中刷新的几个方法的对比)
    在上面也提到了控制RecyclerView增加和删除的动画是通过ItemAnimator这个类来实现的,ItemAnimator这类也是个抽象的类,系统默认给我们提供了一种增加和删除的动画,下面我们就来看看这种动画的效果,我们需要做的修改如下:
LinearLayoutManager layoutManager = new LinearLayoutManager(this);  
//设置布局管理器  
recyclerView.setLayoutManager(layoutManager);  
//设置增加或删除条目的动画  
recyclerView.setItemAnimator( new DefaultItemAnimator());
    然后重写ActionBar的:
     @Override  
     public boolean onCreateOptionsMenu(Menu menu)  
     {  
           getMenuInflater().inflate(R.menu. main, menu);  
            return super.onCreateOptionsMenu(menu);  
     }  
  
     @Override  
     public boolean onOptionsItemSelected(MenuItem item)  
     {  
            switch (item.getItemId())  
           {  
            case R.id. id_action_add:  
                 recycleAdapter.addData(1);  
                 break;  
            case R.id. id_action_delete:  
                 recycleAdapter.removeData(1);  
                 break;  
           }  
            return true;  
     }
    关于R.menu. main中的main.xml这个文件代码就不贴了,在最后的一个汇总的例子里会有.
    recyclerViewAdapter中增加的两个方法:
   public void addData( int position) {
          mDatas.add(position, "Insert One");
          notifyItemInserted(position);
          notifyItemRangeChanged(position, mDatas.size());
     }

     public void removeData( int position) {
          mDatas.remove(position);
          notifyItemRemoved(position);
          notifyItemRangeChanged(position, mDatas.size());
     }
    RecyclerView.Adapter中刷新数据的几个方法,一共有这么几个方法:
    //这个方法跟我们平时用到的ListView的Adapter的方法一样,这里就不多做描述了。
public final void notifyDataSetChanged()  
    //当position位置的数据发生了改变时就会调用这个方法,就会回调对应position的
onBindViewHolder()方法了,当然,因为ViewHolder是复用的,所以如果position在当前屏幕以外,也就不会回调了,因为没有意义,下次position滚动会当前屏幕以内的时候同样会调用
onBindViewHolder()方法刷新数据了。其他的方法也是同样的道理。
public final void notifyItemChanged(int position)  
    //可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。
public final void notifyItemRangeChanged(int positionStart, int itemCount)  

    //是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。
public final void notifyItemInserted(int position)  
    //是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新。
public final void notifyItemMoved(int fromPosition, int toPosition)  
    //批量添加。
public final void notifyItemRangeInserted(int positionStart, int itemCount)  
    //第position个被删除的时候刷新,同样会有动画。
public final void notifyItemRemoved(int position) 
    //批量删除。 
public final void notifyItemRangeRemoved(int positionStart, int itemCount)
七.给RecyclerView的Item添加点击事件
    到这里还有一点到现在我们都没有提及,就是Item的点击事件RecyclerView监听事件处理在ListView使用的时候,该控件给我们提供一个onItemClickListener监听器,这样当我们点击Item的时候,会回调相关的方法,以便我们方便处理Item点击事件。对于RecyclerView来讲,非常可惜的是,该控件没有给我们提供这样的内置监听器方法,不过我们可以进行改造实现,可以这样实现Item的点击事件的监听,在我们的adapter中增加这两个方法:
     public interface OnItemClickListener{
        void onClick( int position);
        void onLongClick( int position);
     }
     public void setOnItemClickListener(OnItemClickListener onItemClickListener ){
        this. mOnItemClickListener=onItemClickListener;
     }
    然后onBindViewHolder方法要做如下更改:
     @Override  
     public void onBindViewHolder(MyViewHolder holder, final int position) {  
             
           holder. tv.setText( mDatas.get(position));  
             
            if( mOnItemClickListener!= null){  
                holder. itemView.setOnClickListener( new OnClickListener() {  
                       
                      @Override  
                      public void onClick(View v) {  
                           mOnItemClickListener.onClick(position);  
                     }  
                });  
                  
                holder. itemView.setOnLongClickListener( new OnLongClickListener() {  
                      @Override  
                      public boolean onLongClick(View v) {  
                           mOnItemClickListener.onLongClick(position);  
                            return false;  
                     }  
                });  
           }  
     }
    在MainAcitivity中增加:
         recycleAdapter.setOnItemClickListener(new OnItemClickListener() {  
               
              @Override  
              public void onLongClick(int position) {  
                   Toast.makeText(MainActivity.this,"onLongClick事件您点击了第:"+position+"个Item",0).show();  
              }  
               
              @Override  
              public void onClick(int position) {  
                   Toast.makeText(MainActivity.this,"onClick事件您点击了第:"+position+"个Item",0).show();  
              }  
         });
    然后运行,效果如下:
    可以看到Item的onClick和onLongClick事件都触发了。到此关于RecyclerView的基本用法就介绍的差不多了,当然,还有几个点没有提到,比方说瀑布流、下拉刷新、上拉加载等,这些在后面的课程中都会给大家呈现。

你可能感兴趣的:(Android中RecyclerView(可以设置瀑布流))