RecyclerView入门
RecyclerView都出来了好久了,由于我负责的一个项目一直都是使用的ListView,所以我都没什么时间去折腾google新出的这个控件,这不,最近刚好有点时间,我就把公司的项目中使用ListView的地方,全部换成了RecyclerView,传说RecycleView比ListView更方便,更利于扩展,哈哈,我也来体验一把。确实比传统的ListView简单的多,虽然代码量比ListView的稍大,但是在扩展性和易用性这点上来说,ListView是远远不如RecycleView的。当然,这并不是说ListView不如RecycleView,它们各有各的优点和缺点,今天我就来带大家RecyclerView的详细介绍。
我们知道,ListView只支持在垂直方向上的滚动,Android API并没有提供ListView其他方式的滚动支持,也许ListView也可以有多种方式去支持其他方式的滚动,但是请相信我,google开发者提供ListView这个控件并不是为了做这些事情的。既然ListView不支持其它方式的滚动信息,而RecycleView支持多种滚动方式,那么其易用性和扩展性显而易见,RecycleView支持多种类型列表的展示要求:主要如下
LinearLayoutManager 线性布局管理器,支持水平方向和竖直方向的滚动列表
StaggeredGridLayoutManager 支持瀑布流式的滚动列表
GridLayoutManager 网格布局的滚动列表
RecycleView 和传统ListView的区别
- ViewHolder: 传统的ListView并不严格要求重写ViewHolder,也就是不严格要求利用缓存,不利用缓存也仅仅只是牺牲了内存,而RecycleView强制要求使用者重写ViewHolder方法。
- 显示效果方面: 在上面我们已经做了介绍,ListView的显示效果非常单一,只能在垂直方向上进行滚动,而RecycleView通过设置不同的布局管理器,可以达到多种滚动效果,瀑布流布局不再是开发者的噩梦。
- 列表项动画:起初的Android API中,删除或添加item时,item是无法产生动画效果的。后面随着Android的进化,Google的Chat Hasse推荐使用 ViewPropertyAnimator 属性动画来实现上述需求。
相比较于ListView, RecyclerView.ItemAnimator 则被提供用于在RecyclerView添加、删除或移动item时处理动画效果。同时,如果你比较懒,不想自定义ItemAnimator,你还可以使用 DefaultItemAnimator 。
看完了上面的优缺点,小伙伴们,尝试着放弃ListView,转向RecyclerView吧。当然RecyclerView也并不是白分之百的完美,它也有它自己的缺点,比如说点击事件需要我们自己去实现,等等。相比较这些缺点而言,还是功大于过,利大于弊。
RecycleView使用方式
老规矩,先看效果图
5.1 系统下的效果图
4.x 系统下的效果图
6.x的我就不测试了,肯定是能够运行的。有兴趣的可以去试一下。录制动画可能掉帧,并不是卡,在真机上很流畅。
下面我们就以这个Demo来看看RecycleView的具体用法,其实真心不难。很多新手觉得难的原因,我想主要是觉得自己写ViewHolder比较难吧,其实不然。下面我就带着大家一起来看看RecycleView究竟有啥可怕的。
1. 添加RecycleView的依赖
compile 'com.android.support:recyclerview-v7:25.1.0' //recycleView的依赖
compile 'com.android.support:cardview-v7:25.1.0' // 这是cardView的依赖
注意: 这里我使用了CardView这个控件,如果不会这个控件,可以不用这个控件
2. 写Activity布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/rv_list"/>
<LinearLayout
android:gravity="bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_linearlayout"
android:layout_weight="1"
android:text="线性(垂直)"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_linearlayout_horizatol"
android:layout_weight="1"
android:text="线性(水平)"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_grid"
android:layout_weight="1"
android:text="网格布局"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn"
android:layout_weight="1"
android:text="瀑布流"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
这里就没什么可说的了,底部用了四个Button按钮,分别是对应的几种布局管理器。
3. 完成RecycleView的子布局 recycleview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:id="@+id/cv_item"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="4dp"
card_view:cardBackgroundColor="#795548"
card_view:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<ImageView
android:id="@+id/iv_pic"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_weight="1"
/>
<TextView
android:id="@+id/tv_text"
android:padding="20dp"
android:textColor="#ffffff"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</android.support.v7.widget.CardView>
这个也没什么好说的,基本上和ListView的子布局一样,唯一有点区别的是,这里我使用了cardView,如果你们不cardView,同样可以直接使用传统的布局即可。cardView只是一个卡片式容器而已,外观上看起来会有一点阴影效果,更加好看一点。(详细参见md设计)
4. 完成RecycleView的Adapter
- 新建RecyclerViewAdapter继承至RecyclerView.Adapter,这里面的VH就代表你自己写的ViewHolder,把你自己重写的ViewHolder填入其中即可。
实现RecyclerView.adapter中的三个方法:
//将视图和ViewHolder绑定 public void onBindViewHolder(VH holder, final int position) // 创建一个自定义的VH试图 public VH onCreateViewHolder(ViewGroup parent, int viewType) //返回条目的个数 public int getItemCount()
代码如下
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.NormalViewHolder> {
private LayoutInflater mLayoutInflater;
private Context mContext;
private String [] mTitle;
private int [] mPic;
//通过构造方法将图片以及文字,上下文传递过去
public RecyclerViewAdapter(Context context,String[]title,int[] pic){
mContext=context;
mTitle=title;
mPic=pic;
mLayoutInflater=LayoutInflater.from(context);
}
//我们创建一个ViewHolder并返回,ViewHolder必须有一个带有View的构造函数,这个View就是我们Item的根布局,在这里我们使用自定义Item的布局;
@Override
public NormalViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new NormalViewHolder(mLayoutInflater.inflate(R.layout.recycler_item,parent,false));
}
//将数据与界面进行绑定的操作
@Override
public void onBindViewHolder(NormalViewHolder holder, final int position) {
holder.mTextView.setText(mTitle[position]);
holder.mImageView.setBackgroundResource(mPic[position]);
holder.mCardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,mTitle[position],Toast.LENGTH_SHORT).show();
}
});
}
//获取数据的数量
@Override
public int getItemCount() {
return mTitle==null ? 0 : mTitle.length;
}
}
5.重写自定义的ViewHolder
这个真是太简单了,简单到你怀疑人生,不信你看看。
//自定义的ViewHolder,持有每个Item的的所有界面元素
public static class NormalViewHolder extends RecyclerView.ViewHolder{
TextView mTextView;
CardView mCardView;
ImageView mImageView;
public NormalViewHolder(View itemView) {
super(itemView);
mTextView=(TextView)itemView.findViewById(R.id.tv_text);
mCardView=(CardView)itemView.findViewById(R.id.cv_item);
mImageView=(ImageView)itemView.findViewById(R.id.iv_pic);
}
}
就是获取控件的实例。除此之外,就没有其它的东西了。
6. 如何使用RecyclerView
在上面的几步中, 我们已经将RecyclerView中的准备工作做完了,接下来我们就来讲一下如何在我们的MainActivity中使用RecyclerView。分三步走
创建一个线性布局管理器
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
设置垂直滚动,也可以设置横向滚动
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
RecyclerView设置布局管理器
mRecyclerView.setLayoutManager(layoutManager);
RecyclerView设置Adapter
mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));
可能有人会说了,你这里明明是4步- -, 哈哈,其实第二步是可以省略的,因为线性布局的默认布局方式就是垂直的,我们写了第二步实际上是多此一举了。
不过如果我们要定义RecyclerView是水平滚动的,那么我们就需要第二步了,此时我们可以这样写:
layoutManager1.setOrientation(LinearLayoutManager.HORIZONTAL);
如果要设置成网格布局,同样也是一行代码就搞定:
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2)); //Grid视图
设置瀑布流布局( 我也不清楚是不是这个叫法,如果叫错了,见谅- -)
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));
现在你知道RecyclerView的好处了吧,要实现不同的滚动效果,只需要一行代码就可以搞定,而不像ListView那样,需要找各种方法去自定义。你现在可以说:RecyclerView就是这么简单,最后贴一下MainActivity的内容
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private RecyclerView mRecyclerView;
private Button mButtonLinearLayout;
private Button mButtonLinearLayoutHorizatol;
private Button mButtonGrid;
private Button mButton;
//item 显示所需
private String[] title = {"路飘零路茫茫烟雨遮不住",
"轻叹江湖岁月无尽处",
"拥着你 匆匆往事诉不尽 ,散不去 好梦难成愁易醒",
"忆往昔 几分心情暗低吟, 当年情 在风中追忆已无影",
"拥着你一切仿佛在梦中",
" 重相逢不堪往事竟已无语, 猛回首 几回浮尘我独饮",
"当年情 化作泪眼烟去"
};
private int[] pic = {R.mipmap.ic_launcher, R.mipmap.ic_launcher,
R.mipmap.ic_launcher, R.mipmap.ic_launcher,
R.mipmap.ic_launcher, R.mipmap.ic_launcher,
R.mipmap.ic_launcher};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.rv_list);
mButtonLinearLayout = (Button) findViewById(R.id.btn_linearlayout);
mButtonLinearLayoutHorizatol = (Button) findViewById(R.id.btn_linearlayout_horizatol);
mButtonGrid = (Button) findViewById(R.id.btn_grid);
mButton = (Button) findViewById(R.id.btn);
mButtonLinearLayout.setOnClickListener(this);
mButtonGrid.setOnClickListener(this);
mButton.setOnClickListener(this);
mButtonLinearLayoutHorizatol.setOnClickListener(this);
// 创建一个线性布局管理器
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//设置垂直滚动,也可以设置横向滚动
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//RecyclerView设置布局管理器
mRecyclerView.setLayoutManager(layoutManager);
//RecyclerView设置Adapter
mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_linearlayout:
// 创建一个线性布局管理器
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//设置垂直滚动,也可以设置横向滚动
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));
break;
case R.id.btn_linearlayout_horizatol:
// 创建一个线性布局管理器
LinearLayoutManager layoutManager1 = new LinearLayoutManager(this);
//设置垂直滚动,也可以设置横向滚动
layoutManager1.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(layoutManager1);
mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));
break;
case R.id.btn_grid:
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2)); //Grid视图
mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));
break;
case R.id.btn:
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));
mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));
break;
}
}
}
最后友情提醒:文字内容是张国荣的当年情的歌词。哈哈。
总结
代码我都给你们贴出来了,一行都不差。所以源码我就不上传了。有兴趣的可以在下面留言Call我。下篇文章我们讲一下RecyclerView加载不同的布局。