过去的这一两年, RecyclerView越来越引起了我们Android开发人员的注意,RecyclerView的灵活性还有性能上有很大的提升。
想必大家或多或少的接触过或者了解过RecyclerView,为什么没有用起来,原因大概如下?
- 大家对于ListView的熟悉、,ListView基本可以满足应用的大部分场景,为什么要换RecyclerView?
- ListView稳定,有很多相关开源库,特别的好用。
- RecyclerView不能添加头布局,而ListView可以。
RecyclerView有什么优缺点?如何使用RecyclerView和解决这些问题?
RecyclerView 的使用和优点
-
布局效果
RecyclerView最大的优势就是灵活,RecyclerView 同时支持 线性布局、网格布局、瀑布流布局三种,而且还能够控制横向还是纵向滚动。
RecyclerView.LayoutManager,这是一个抽象类,系统提供了3个实现类:
- LinearLayoutManager 线性管理器,支持横向、纵向。
- GridLayoutManager 网格布局管理器
- StaggeredGridLayoutManager 瀑布就式布局管理器
注意:在实例化RecyclerView之后,我们需要使用setLayoutManager()
给它设置布局管理器
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); // 创建线性布局管理器
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 设置线性布局为横向(默认为纵向)
mRecyclerView.setLayoutManager(linearLayoutManager); // 设置布局管理器
-
自带ViewHolder
RecyclerView.Adapter,比BaseAdapter做了更好的封装,强制需要创建ViewHolder,这样的好处就是避免了初学者写性能不佳的代码
继承重写 RecyclerView.Adapter 和 RecyclerView.ViewHolder
// 第一步:继承重写 RecyclerView.Adapter 和 RecyclerView.ViewHolder
public class AuthorRecyclerAdapter extends RecyclerView.Adapter<AuthorRecyclerAdapter.AuthorViewHolder> {
@Override
public AuthorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return viewHolder;
}
@Override
public void onBindViewHolder(AuthorViewHolder holder, int position) {
}
@Override
public int getItemCount() {
if (list == null) {
return 0;
}
return list.size();
}
class AuthorViewHolder extends RecyclerView.ViewHolder {
public AuthorViewHolder(View itemView) {
super(itemView);
}
}
}
-
控制item的间隔分割线,
可以使用addItemDecoration(ItemDecoration decor)
,不过里边的ItemDecoration是一个抽象类,需要自己去实现
-
实现增删动画
通过setItemAnimator(ItemAnimator animator)
可以实现增删动画
RecyclerView自带添加、删除动画,而ListView则需添加额外的代码才能实现。
删除调用RecyclerView的adapter的notifyItemRemoved
添加调用RecyclerView的adapter的notifyItemInserted
说到adapter我们就来说说RecyclerView.Adapter和BaseAdapter相比,额外提供了一下这些方法:
// 数据发生了改变,那调用这个方法,传入改变对象的位置。
public final void notifyItemChanged(int position);
// 可以刷新从positionStart开始itemCount数量的item了
public final void notifyItemRangeChanged(int positionStart, int itemCount);
// 添加,传入对象的位置。
public final void notifyItemInserted(int position);
// 删除,传入对象的位置。
public final void notifyItemRemoved(int position);
// 对象从fromPosition移动到toPosition
public final void notifyItemMoved(int fromPosition, int toPosition);
//批量添加
public final void notifyItemRangeInserted(int positionStart, int itemCount);
//批量删除
public final void notifyItemRangeRemoved(int positionStart, int itemCount);
如何为RecyclerView添加Header和Footer
- 在MyAdapter类中,提供setHeaderView()和setFooterView()两个方法,我们就是通过这两个方法从Activity将headerView和footerView传递过来的,利用getItemViewType()返回Item的类型,根据不同的类型,我们创建不同的Item的View。
package com.study.wnw.recyclerviewheaderfooter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
/** * Created by wnw on 16-5-20. */
public class MyAdapter extendsRecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int TYPE_HEADER = 0; //说明是带有Header的
public static final int TYPE_FOOTER = 1; //说明是带有Footer的
public static final int TYPE_NORMAL = 2; //说明是不带有header和footer的
//获取从Activity中传递过来每个item的数据集合
private List<String> mDatas;
//HeaderView, FooterView
private View mHeaderView;
private View mFooterView;
//构造函数
public MyAdapter(List<String> list){
this.mDatas = list;
}
//HeaderView和FooterView的get和set函数
public View getHeaderView() {
return mHeaderView;
}
public void setHeaderView(View headerView) {
mHeaderView = headerView;
notifyItemInserted(0);
}
public View getFooterView() {
return mFooterView;
}
public void setFooterView(View footerView) {
mFooterView = footerView;
notifyItemInserted(getItemCount()-1);
}
/** 重写这个方法,很重要,是加入Header和Footer的关键,我们通过判断item的类型,从而绑定不同的view * */
@Override
public int getItemViewType(int position) {
if (mHeaderView == null && mFooterView == null){
return TYPE_NORMAL;
}
if (position == 0){
//第一个item应该加载Header
return TYPE_HEADER;
}
if (position == getItemCount()-1){
//最后一个,应该加载Footer
return TYPE_FOOTER;
}
return TYPE_NORMAL;
}
//创建View,如果是HeaderView或者是FooterView,直接在Holder中返回
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(mHeaderView != null && viewType == TYPE_HEADER) {
return new ListHolder(mHeaderView);
}
if(mFooterView != null && viewType == TYPE_FOOTER){
return new ListHolder(mFooterView);
}
View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new ListHolder(layout);
}
//绑定View,这里是根据返回的这个position的类型,从而进行绑定的, HeaderView和FooterView, 就不同绑定了
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(getItemViewType(position) == TYPE_NORMAL){
if(holder instanceof ListHolder) {
//这里加载数据的时候要注意,是从position-1开始,因为position==0已经被header占用了
((ListHolder) holder).tv.setText(mDatas.get(position-1));
return;
}
return;
}else if(getItemViewType(position) == TYPE_HEADER){
return;
}else{
return;
}
}
//在这里面加载ListView中的每个item的布局
class ListHolder extends RecyclerView.ViewHolder{
TextView tv;
public ListHolder(View itemView) {
super(itemView);
//如果是headerview或者是footerview,直接返回
if (itemView == mHeaderView){
return;
}
if (itemView == mFooterView){
return;
}
tv = (TextView)itemView.findViewById(R.id.item);
}
}
//返回View中Item的个数,这个时候,总的个数应该是ListView中Item的个数加上HeaderView和FooterView
@Override
public int getItemCount() {
if(mHeaderView == null && mFooterView == null){
return mDatas.size();
}else if(mHeaderView == null && mFooterView != null){
return mDatas.size() + 1;
}else if (mHeaderView != null && mFooterView == null){
return mDatas.size() + 1;
}else {
return mDatas.size() + 2;
}
}
}
- 在Activity添加布局
mMyAdapter.setHeaderView(header);
mMyAdapter.setFooterView(footer);
如何给RecyclerView添加点击事件
RecyclerView强大,好用,但是使用率很高的ItemClickListener却没有添加。
点击事件的实现,有常见的三种方法:
- 通过 RecyclerView已有的方法 addOnItemTouchListener()实现
- 在创建 ItemView时添加点击监听
- 当 ItemViewattach RecyclerView时实现
具体参考:给RecyclerView封装个Adapter吧(更优雅的添加点击事件)
更多功能介绍将持续更新中。。。。。。
参考文献 及相关框架:
基础篇:
扩展:
-
twoway-view 封装了RecyclerView常用方法,如click等等,以及支持了更多不同的布局,使得RecyclerView使用起来更简单!