您的位置:首页 > 移动开发 > Android开发

【Android】RecyclerView详解(一)

2016-06-01 17:00 357 查看


1.介绍

RecyclerView是比 ListView 更高级且更具灵活性的组件。 此组件是一个用于显示庞大数据集的容器,可通过保持有限数量的视图进行非常有效的滚动操作。 如果您有数据集合,其中的元素将因用户操作或网络事件而发生改变,请使用 RecyclerView 小组件。

RecyclerView使用起来很方便因为它:

提供了一种插拔式的体验,高度的解耦,异常的灵活使用;

显示的样式更丰富包括水平,竖直,Grid,瀑布显示方式;

可以通过ItemDecoration自定义Item间的间隔;

可以通过ItemAnimator自定义Item增、删动画(也可设置默认动画);

代码内聚不需要手动创建ViewHolder;

2.基本使用

首先要用这个控件,你需要在gradle文件中添加包的引用

compile 'com.android.support:recyclerview-v7:23.4.0'


在xml中添加RecyclerView组件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
tools:context="test.wangkeke.com.androidrecyclerviewdemo.NormalActivity">

<android.support.v7.widget.RecyclerView
android:id="@+id/my_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

</RelativeLayout>


构造适配器Adapter:

public class NormalRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private Context context;

private final LayoutInflater mLayoutInflater;

private String[] mTitles;

public NormalRecyclerViewAdapter(Context context)
{
mTitles = context.getResources().getStringArray(R.array.sports);
this.context = context;
mLayoutInflater = LayoutInflater.from(context);
}

/**
* 导入布局文件
* @param parent
* @param viewType
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
return new NormalTextViewHolder(mLayoutInflater.inflate(R.layout.item,parent,false));
}

/**
* 绑定数据
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
((NormalTextViewHolder)holder).text.setText(mTitles[position]);
//将数据保存在itemView的Tag中,以便点击时进行获取
((NormalTextViewHolder)holder).layout.setTag(mTitles[position]);
}

@Override
public int getItemCount()
{
return mTitles.length;
}

public class NormalTextViewHolder extends  RecyclerView.ViewHolder
{
private TextView text;

private RelativeLayout layout;

public NormalTextViewHolder(View itemView)
{
super(itemView);
text = (TextView) itemView.findViewById(R.id.text);

layout = (RelativeLayout) itemView.findViewById(R.id.layout);

layout.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Toast.makeText(context, ""+v.getTag(), Toast.LENGTH_SHORT).show();
}
});

}
}
}


.RecyclerView.Adapter主要用于处理数据集合并负责绑定视图;ViewHolder持有item所有的用于绑定数据的View;

item.xml布局,就一个textView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
>
<RelativeLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textStyle="bold"/>
</RelativeLayout>
</LinearLayout>


activity中进行简单的设置:

recyclerView = (RecyclerView) findViewById(R.id.my_recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new NormalRecyclerViewAdapter(this);
recyclerView.setAdapter(adapter);


效果图:



recyclerview提供这些内置的布局管理器:

inearlayoutmanager 显示垂直滚动列表或水平的项目。

gridlayoutmanager 显示在一个网格项目。

staggeredgridlayoutmanager 显示在交错网格项目。

- 设置layoutmanager为gridlayoutmanager时,效果如下:



Staggeredgridlayoutmanager 这个效果大家可以自己试试,后面也会介绍;

2.添加分割线

突然发现列表出来是出来了,可是,没有分割线啊,不要惊慌,recyclerView需要单独处理分割线,提供了下面这个方法用来设置分割线的风格:

recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));


下面是官方给的分割线的例子,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);
RecyclerView v = new RecyclerView(
parent.getContext());
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);
}
}
}


效果图:



3.加载不同的View

开始之前,这里要注意的就是函数onCreateViewHolder(ViewGroup parent, int viewType)这里的第二个参数就是View的类型,可以根据这个类型判断去创建不同item的ViewHolder。我们可以通过重写 getItemViewType方法是用来获取当前项Item(position参数)是哪种类型的布局。

本例子结合cardview来实现,对cardview不熟悉的同学可以看下cardview讲解

主xml布局很简单,就一个RecyclerView组件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
tools:context="test.wangkeke.com.androidrecyclerviewdemo.NormalActivity">

<android.support.v7.widget.RecyclerView
android:id="@+id/type_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

</RelativeLayout>


item布局文件item_image.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
app:cardBackgroundColor="@android:color/white"
app:cardCornerRadius="5dp"
app:cardElevation="5dp"
app:contentPadding="5dip">

<LinearLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">

<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:layout_centerInParent="true"/>

<TextView
android:id="@+id/image_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/image"
android:layout_marginTop="10dp"
android:text="test"
android:textStyle="bold"
android:gravity="center"/>

</LinearLayout>
</android.support.v7.widget.CardView>


关键的adapter代码:

public class TypeRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private String imageOne = "http://5.133998.com/2014/pic/000/363/18107c4b46aa8a182776746ff43e49bf.jpg";
private String imageTwo = "http://img3.imgtn.bdimg.com/it/u=3954782107,4019560836&fm=21&gp=0.jpg";

private boolean flag = false;

public static enum ITEM_TYPE {
ITEM_TYPE_IMAGE,
ITEM_TYPE_TEXT
}

private Context context;

private final LayoutInflater mLayoutInflater;

private String[] mTitles;

public TypeRecyclerViewAdapter(Context context)
{
mTitles = context.getResources().getStringArray(R.array.sports);
this.context = context;
mLayoutInflater = LayoutInflater.from(context);
}

/**
* 导入布局文件
* @param parent
* @param viewType
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
if (viewType == ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal()) {
return new ImageViewHolder(mLayoutInflater.inflate(R.layout.item_image, parent, false));
} else {
return new NormalTextViewHolder(mLayoutInflater.inflate(R.layout.item_card, parent, false));
}
}

/**
* 绑定数据
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
//判断holder的类型,来显示不同的View
if (holder instanceof NormalTextViewHolder) {
((NormalTextViewHolder) holder).text.setText(mTitles[position]);
//将数据保存在itemView的Tag中,以便点击时进行获取
((NormalTextViewHolder) holder).layout.setTag(mTitles[position]);
} else if (holder instanceof ImageViewHolder) {
((ImageViewHolder)holder).textView.setText(mTitles[position]);
//将数据保存在itemView的Tag中,以便点击时进行获取
((ImageViewHolder)holder).layout.setTag(mTitles[position]);

/**
* 交叉加载图片,测试用
*/
if(flag)
{
ImageLoader.getInstance().displayImage(imageOne,((ImageViewHolder)holder).imageView);
flag = !flag;
}
else
{
ImageLoader.getInstance().displayImage(imageTwo,((ImageViewHolder)holder).imageView);
flag = !flag;
}
}
}

@Override
public int getItemCount()
{
return mTitles.length;
}

@Override
public int getItemViewType(int position) {
//返回类型标记
return position % 2 == 0 ? ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal() : ITEM_TYPE.ITEM_TYPE_TEXT.ordinal();
}

/**
* 纯textView布局holder
*/
public class NormalTextViewHolder extends  RecyclerView.ViewHolder
{
private TextView text;

private RelativeLayout layout;

public NormalTextViewHolder(View itemView)
{
super(itemView);
text = (TextView) itemView.findViewById(R.id.text);

layout = (RelativeLayout) itemView.findViewById(R.id.layout);

layout.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Toast.makeText(context, ""+v.getTag(), Toast.LENGTH_SHORT).show();
}
});

}
}

/**
* 带图片的布局holder
*/
public class ImageViewHolder extends  RecyclerView.ViewHolder
{
private TextView textView;

private ImageView imageView;

private LinearLayout layout;

public ImageViewHolder(View itemView)
{
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.image);
textView = (TextView) itemView.findViewById(R.id.image_text);
layout = (LinearLayout) itemView.findViewById(R.id.layout);

layout.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Toast.makeText(context, ""+v.getTag(), Toast.LENGTH_SHORT).show();
}
});
}
}
}


Activity中进行绑定和显示:

recyclerView = (RecyclerView) findViewById(R.id.type_recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new TypeRecyclerViewAdapter(this);
recyclerView.setAdapter(adapter);


效果图:



4.插入删除动画

RecyclerView提供了设置动画的方法,我们只需要通过setItemAnimator方法即可设置Item插入和删除的动画;

//添加默认动画
recyclerView.setItemAnimator(new DefaultItemAnimator());


之前的数据源用的是个String数组,无法添加数据,转为list后添加;

/**
* 添加数据
* @param content
* @param position
*/
public void addItem(String content, int position) {
titleList.add(position,content);
notifyItemInserted(position); //Attention!
}

/**
* 删除数据
* @param content
*/
public void removeItem(String content) {
int position = titleList.indexOf(content);
titleList.remove(position);
notifyItemRemoved(position);//Attention!
}


效果图:



基本使用先介绍这么多,欢迎看官批评讨论!

源码下载

参考连接:

1.RecyclerView使用详解

2.RecyclerView点滴

3.RecyclerView使用介绍
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: