【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使用介绍
相关文章推荐
- Android AsyncTask两种线程池分析和总结
- Android 自定义View属性相关细节
- Android之项目中JNI调用已有的Android平台so库
- Android listview动态加载列表项实现代码
- ubuntu15.04系统下安装android studio
- Android中 4.4-5.0 系统状态栏颜色的修改。实现Translucent System Bar
- android 6.0 sd卡读取文件失败
- 解决Android SDK下载慢,国内Google被墙问题 AndroidSDK镜像源 下载
- Android开发MVP模式入门
- SurfaceFlinger 分析 一
- Android Tabhost使用方法详解
- Android自定义控件之对原生控件的拓展
- Activity与Service通信之自定义接口
- Activity与Service通信之EventBus
- android在布局文件中自定义参数并在初始化时获取
- Android--Butter Knife
- Ionic项目中使用极光推送-android
- 详解Android进程和线程
- Android软键盘的隐藏与显示
- Android之沉浸式状态栏的实现