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
效果图
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的基本用法就介绍的差不多了,当然,还有几个点没有提到,比方说瀑布流、下拉刷新、上拉加载等,这些在后面的课程中都会给大家呈现。