RecyclerView是比 ListView 更高级且更具灵活性的组件。 此组件是一个用于显示庞大数据集的容器,可通过保持有限数量的视图进行非常有效的滚动操作。 如果您有数据集合,其中的元素将因用户操作或网络事件而发生改变,请使用 RecyclerView 小组件。
RecyclerView使用起来很方便因为它:
compile 'com.android.support:recyclerview-v7:23.4.0'
<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>
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;
<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>
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 这个效果大家可以自己试试,后面也会介绍;
突然发现列表出来是出来了,可是,没有分割线啊,不要惊慌,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);
}
}
}
效果图:
开始之前,这里要注意的就是函数onCreateViewHolder(ViewGroup parent, int viewType)这里的第二个参数就是View的类型,可以根据这个类型判断去创建不同item的ViewHolder。我们可以通过重写 getItemViewType方法是用来获取当前项Item(position参数)是哪种类型的布局。
本例子结合cardview来实现,对cardview不熟悉的同学可以看下cardview讲解;
<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>
<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>
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();
}
});
}
}
}
recyclerView = (RecyclerView) findViewById(R.id.type_recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new TypeRecyclerViewAdapter(this);
recyclerView.setAdapter(adapter);
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使用介绍