介绍

RecyclerView是ListView的豪华增强版。它主要包含以下几处新的特性,如ViewHolder,ItemDecorator,LayoutManager,SmothScroller以及增加或删除item时item动画等。官方推荐我们采用RecyclerView来取代ListView。

相对优势

  • ViewHolder

    ListView需要自己实现ViewHolder来提高性能,或者不使用ViewHolder,但是使用ViewHolder来绑定对象是一个很好的习惯。RecyclerView很好的帮我们解决了这个问题,RecyclerView.ViewHolder在使用RecyclerView过程中必须实现,因为它是一个抽象类无法直接创建,需要自己完成对应子类的建立然后使用


  • LayoutManager

    ListView只能在垂直方向上滚动,不支持其他的滚动方式,当然开发者有很多自定义的方式完成这些功能,这里就不做争辩,从设计的角度上看,ListView设计之初应该就没有想过让它完成这些复杂的功能,只是为了单纯的列表显示。但是RecyclerView相较于ListView,在滚动上面的功能扩展了许多。它可以支持多种类型列表的展示要求,主要如下:

    GridLayoutManager ,支持网格展示,可以水平或者竖直滚动,如展示图片的画廊。

    LinearLayoutManager ,可以支持水平和竖直方向上滚动的列表。

    StaggeredGridLayoutManager ,可以支持交叉网格风格的列表,类似于瀑布流或者Pinterest。


  • ItemAnimation

    ItemAnimation是RecyclerView中子项在增加,删除或者移动的情况下显示的动画效果,Google越来越重视用户体验,从属性动画的推出开始,这就是一个趋势,开发者在这里可以自己实现自己想要添加的动画效果,当然,如果你是个懒汉,请使用new DefaultItemAnimator()


  • ItemDecoration

    ItemDecoration,名字起的很文艺,子项的装饰,RecyclerView在默认情况下并不在item之间展示间隔符。如果你想要添加间隔符,你必须使用RecyclerView.ItemDecoration类来实现。懒汉请使用DividerItemDecoration.java

Recycler示例

实际效果图

上面这个效果图是使用的StaggeredGridLayoutManager

代码层面

布局文件

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorMainBackground"> <include layout="@layout/toolbar"></include> <FrameLayout 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=".model.View.MainActivity"> <android.support.v7.widget.RecyclerView
android:id="@+id/rv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> <android.support.design.widget.FloatingActionButton
android:id="@+id/fab_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginBottom="30dp"
android:layout_marginRight="30dp"
android:src="@drawable/addone" /> <android.support.design.widget.FloatingActionButton
android:id="@+id/fab_del"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:layout_marginBottom="30dp"
android:layout_marginLeft="30dp"
android:src="@drawable/delone" />
</FrameLayout>
</LinearLayout>

recycler_item.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"> <android.support.v7.widget.CardView
android:layout_margin="10dp"
android:id="@+id/cv_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="5dp">
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" /> </android.support.v7.widget.CardView> </FrameLayout>

主Activity

public class MainActivity extends AppCompatActivity {
@Bind(R.id.rv_content)
RecyclerView rvContent;
@Bind(R.id.fab_add)
FloatingActionButton fabAdd;
@Bind(R.id.fab_del)
FloatingActionButton fabDel;
@Bind(R.id.root_layout)
LinearLayout rootLayout; private LayoutManager mLayoutManager; //LayoutManager
private RVAdapter recyclerAdapter; //RecyclerView对应的Adapter
private ArrayList<String> mContentList; //内容list这里只是使用了字符串,当然也可以替换成其他的JavaBean类
private Random mRandom = new Random(); //用于产生随机字符串
private int mSum = 50; //初始化子项数目 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this); //ButterKnife注入,减少代码负担 mContentList = new ArrayList<String>();
for (int i = 0; i < mSum; i++) {
mContentList.add(getRandomString());
} //随机生成数据
recyclerAdapter = new RVAdapter(mContentList);
mLayoutManager = new StaggeredGridLayoutManager(3, LinearLayoutManager.VERTICAL); //3列纵向
rvContent.setAdapter(recyclerAdapter);
rvContent.setLayoutManager(mLayoutManager);
rvContent.setItemAnimator(new DefaultItemAnimator()); //设置动画效果,可以看下上面的效果图,动画效果还是比较明显的
} @OnClick({R.id.fab_add, R.id.fab_del})
public void onClick(View view) {
switch (view.getId()) {
case R.id.fab_add:
recyclerAdapter.addData(1); //加一个
makeSnackBar(rootLayout, "添加一个 :)", null, null);//显示一个Snackbar
break;
case R.id.fab_del:
recyclerAdapter.removeData(1); //去掉一个
makeSnakeBar(rootLayout, "删除一个 :(", null, null); //显示一个Snackbar
break;
default:
break;
}
}
//用于产生随机字符串的方法
public String getRandomString() {
String src = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder dst = new StringBuilder(4);
for (int i = 0; i < 4; i++) {
dst.append(src.charAt(mRandom.nextInt(62)));
}
return dst.toString();
} //构建一个Snackbar并显示出来
private void makeSnackBar(View view, String message, String buttonText, View.OnClickListener onClickListener) {
Snackbar.make(view, message, Snackbar.LENGTH_SHORT)
.setAction(buttonText, onClickListener)
.show();
}
}

适配器

public class RVAdapter extends RecyclerView.Adapter<RVAdapter.MyViewHolder>{
ArrayList<String> mContentList;
Random mRandom = new Random();
//ViewHolder继承自RecyclerView.ViewHolder 子View拿到方便后面访问
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;
CardView cardView;
public MyViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.tv_name);
cardView = (CardView) itemView.findViewById(R.id.cv_bg);
}
}
public RVAdapter(ArrayList<String> mContentList) {
this.mContentList = mContentList;
}
//创建ViewHolder,由于RecyclerView.ViewHolder是一个抽象类无法实例化,所以必须实现一个子类才能使用,这里自己尝试的过程中走了一些弯路,注意inflate最后一个参数设置成false不然可能会出现crash
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
return new MyViewHolder(view);
} //onBindView 用于设置需要显示的View中的内容和一些属性值
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.cardView.setCardBackgroundColor(getRandomColor());
holder.textView.setText(mContentList.get(position));
holder.itemView.getLayoutParams().height = getRandomHeight(200,400);//产生随机高度,看上去像瀑布
} @Override
public int getItemCount() {
return mContentList.size();
} //产生随机颜色
private int getRandomColor() {
return (0xff000000|mRandom.nextInt(0x00ffffff));
}
//产生随机高度
private int getRandomHeight(int min , int max) {
return (mRandom.nextInt(max - min) + min );
}
//添加一个子项
public void addData(int position) {
mContentList.add(position, "Insert One");
notifyItemInserted(position);//不调用这个没有动画效果
}
//删除一个子项
public void removeData(int position) {
mContentList.remove(position);
notifyItemRemoved(position);//不调用这个没有动画效果
}
}

需要注意的几个地方:

1. 实现自己的ViewHolder继承recyclerView,ViewHolder,因为抽象类不能实例化

2. inflate子项的时候,最后一个参数设置成false

3. 动画效果需要在Adapter中调用notifyItem***方法才行

StaggeredGridLayoutManager的效果图上面已经有显示了


其他效果

LinearLayoutManager效果图

对应修改代码

mLayoutManager = new LinearLayoutManager(this);
rvContent.addItemDecoration(new DividerItemDecoration(this, StaggeredGridLayoutManager.VERTICAL));


GridLayoutManager效果图

对应修改代码

mLayoutManager = new GridLayoutManager(this, 3);//3列
rvContent.addItemDecoration(new DividerItemDecoration(this, StaggeredGridLayoutManager.VERTICAL));

StaggeredGridLayoutManager.HORIZONTAL横向的效果图

对应修改代码

mLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.HORIZONTAL);

RVAdapter.java中onBindViewHolder
holder.itemView.getLayoutParams().width = getRandomHeight(200,400);

关于ItemDecoration

这里附上Google Sample中的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 +
Math.round(ViewCompat.getTranslationY(child));
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 +
Math.round(ViewCompat.getTranslationX(child));
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源码中有很多关于这些View的使用方法,大家可以查阅并参考使用。

博文中部分代码:

http://download.csdn.net/detail/poorkick/9541326

<Android 基础(四)> RecyclerView的更多相关文章

  1. RecyclerView使用大全

    RecylerView介绍 RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字recyler ...

  2. 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载

    title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...

  3. 安卓易学,爬坑不易——腾讯老司机的RecyclerView局部刷新爬坑之路

    针对手游的性能优化,腾讯WeTest平台的Cube工具提供了基本所有相关指标的检测,为手游进行最高效和准确的测试服务,不断改善玩家的体验.目前功能还在免费开放中. 点击地址:http://wetest ...

  4. Android Studio开发RecyclerView遇到的各种问题以及解决(二)

    开发RecyclerView时候需要导入别人的例子,我的是从github导入的,下载下github的压缩包之后解压看你要导入的文件是priject还是Module.(一般有app文件夹的大部分是pro ...

  5. Android Studio开发RecyclerView遇到的各种问题以及解决(一)

    以前一直在用ListView,,,最近才看RecyclerView发现好强大.RecyclerView前提是Android版本在5.0以上,本人以前用的是eclipse只支持到4.4.索性就安装一个A ...

  6. Android的Kotlin秘方(II):RecyclerView 和 DiffUtil

    作者:Antonio Leiva 时间:Sep 12, 2016 原文链接:http://antonioleiva.com/recyclerview-diffutil-kotlin/ 如你所知,在[支 ...

  7. Android RecyclerView 实现支付宝首页效果

    Android RecyclerView 实现支付宝首页效果 [TOC] 虽然我本人不喜欢支付宝的,但是这个网格本身其实还是不错的,项目更新中更改了一个布局为网格模式,类似支付宝.(估计是产品抄袭的= ...

  8. Android开发学习之路-RecyclerView滑动删除和拖动排序

    Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...

  9. 打造android偷懒神器———RecyclerView的万能适配器

    转载请注明出处谢谢:http://www.cnblogs.com/liushilin/p/5720926.html 很不好意思让大家久等了,本来昨天就应该写这个的,无奈公司昨天任务比较紧,所以没能按时 ...

  10. 安卓v7支持包下的ListView替代品————RecyclerView

    RecyclerView这个控件也出来很久了,相信大家也学习的差不多了,如果还没学习的,或许我可以带领大家体验一把这个艺术般的控件. 项目已经同步至github:https://github.com/ ...

随机推荐

  1. spring 4.0 JUnit简单的Dao,Service测试

    1.AbstractTransactionalJUnit4SpringContextTests 和AbstractJUnit4SpringContextTests.我们在测试用例类要继承两种中的一个. ...

  2. RStudio 断点调试 进入for循环语句调试

    参考: http://www.rstudio.com/ide/docs/debugging/overview 1.进入调试模式 全选代码,点击source即可进入调试模式. 2.进入for 调试 在F ...

  3. pig flatten

    今天通过不断的尝试,终于知道这个flatten的用法了.其实吧,有时候关键是要test,才能充分理解解说.不过,同事给说的有点问题,误导了我.整的我一直没明白怎么回事. 这是官方的解释: The FL ...

  4. SDUT2140图结构练习——判断给定图是否存在合法拓扑序列

    拓扑序列的判断方法为不存在有向环,代码实现的话有两种,一种是直接去判断是否存在环,较为难理解一些,另一种的话去判断结点入度,如果存在的入度为0的点大于一个,则该有向图肯定不存在一个确定的拓扑序列 #i ...

  5. ubuntu14编译SSF(ethzasl_sensor_fusion )

    参考:http://wiki.ros.org/ethzasl_sensor_fusion 1. cd catkin_ws/src/ 2 git clone git://github.com/ethz- ...

  6. SCUT - 337 - 岩殿居蟹 - 线段树 - 树状数组

    https://scut.online/p/337 这个东西是个阶梯状的.那么可以考虑存两棵树,一棵树是阶梯的,另一棵树的平的,随便一减就是需要的阶梯. 优化之后貌似速度比树状数组还惊人. #incl ...

  7. uoj #5. 【NOI2014】动物园

    #5. [NOI2014]动物园 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的园长决定开设算法班,让 ...

  8. 监听Listener的简介及分类

    一.监听器简介 > Listener是JavaWeb中三大组件之一.Servlet.Filter.Listener > 三大组件都有的共同特点,都需要实现一个接口,并在web.xml文件配 ...

  9. 洛谷P2486 [SDOI2011]染色

    题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例#1: 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C ...

  10. 5、python数据类型之元组(tuple)

    元组 元组和列表最大的区别是元组中的元素固定,元组不能修改,所以不能对元组进行增.删.改 1.创建 tu = (11,22,33) tu = tuple(11,22,33) tu = tuple([] ...