欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android开发--RecyclerView使用,看AndroidL新特性,,概述首先,让我们来看一下

来源: 开发者 投稿于  被查看 1276 次 评论:273

Android开发--RecyclerView使用,看AndroidL新特性,,概述首先,让我们来看一下


在去年Google I/0大会,Google开放了一个全新的视图类RecyclerView,它被用来代替ListView以及GridView,提供更为高效的回收复用机制,同时实现管理与视图的解耦合,今天对这个新的控件来进行一次总结。

概述

首先,让我们来看一下RecyclerView类之下都有哪些重要的类,以及他们的作用:

  • RecyclerView.Adapter:托管数据集合,为每个Item创建视图;

  • RecyclerView.ViewHolder:承载Item视图的子视图;

  • RecyclerView.LayoutManager:负责Item视图的布局;

  • RecyclerView.ItemDecoration:为每个Item视图添加子视图,在Demo中被用来绘制Divider;

  • RecyclerView.ItemAnimator:负责添加、删除数据时的动画效果;

基本用法

首先让我来看一下RecyclerView的基本用法:

20150423122732763.gif

1.创建一个线性布局管理器LayoutManager

// 创建一个线性布局管理器
mLayoutManager = new LinearLayoutManager(this);
// 默认是Vertical,可以不写
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);

2.重新一个adapter继承RecyclerView.Adapter《VH》,VH就表示我们平时在ListView中用的ViewHolder类(该类必须继承RecyclerView.ViewHolder);

在adapter中有几个重要的方法需要我们自己补充:

  • public int getItemCount():返回显示Item总数;

  • public void onBindViewHolder(ViewHolder vh, int position):绑定View到Item上vh就是我们在继承RecyclerView.Adapter传入的VH类型,在这个方法中处理数据显示到Item上;

  • public ViewHolder onCreateViewHolder(ViewGroup view, int position):在该方法中我们创建一个ViewHolder并返回,ViewHolder必须有一个带有View的构造函数,这个View就是我们Item的根布局,在这里我们可以自定义Item的布局;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<String> dataList;   
    public MyAdapter(List<String> list) {        
        this.dataList = list;
    }

    @Override    
    public int getItemCount() {        
        // TODO Auto-generated method stub
        return dataList.size();
    }

    @Override    
    public void onBindViewHolder(ViewHolder viewHolder, int position){        
        // TODO Auto-generated method stub
        viewHolder.textView.setText(dataList.get(position));
    }

    @Override    
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {        
        // TODO Auto-generated method stub
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(
                R.layout.item, null);
        ViewHolder holder = new ViewHolder(view);        return holder;
    }    public class ViewHolder extends RecyclerView.ViewHolder {

    public TextView textView;        
    public ViewHolder(View view) {            
        super(view);            // TODO Auto-generated constructor stub
        textView = (TextView) view.findViewById(R.id.item_text);
    }

}

3.设置数据集

List<String> list = new ArrayList<String>();
for (int i = 0; i < 100; i++) {    
    list.add("item  "+ i);
}
MyAdapter adapter = new MyAdapter(list);
mRecyclerView.setAdapter(adapter);

改变LinearLayoutManager的方向可以设置为横向的ListView显示,这也是RecyclerView的强大之处,可以实现回收管理和视图的解耦。

mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

如何为Item添加分割线

简单的使用之后我们看到的RecyclerView连基本的分割线都没有,接下来就来看看如何为它添加分割线吧:使用addItemDecoration方法可以为RecyclerView添加一个ItemDecoration,利用ItemDecoration为我们绘制分割线。

ItemDecoration下有三个方法,ItemDecoration并没有对其实现,需要我们自己完成:

  • onDraw方法:其绘制将会在每个Item被绘制之前进行;

  • onDrawOver:在绘制完Item后进行绘制;

  • getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量;

让我们来看看代码:

public class ItemDivider extends ItemDecoration {

    private Drawable mDrawable;    
    public ItemDivider(Context context, int resId) {       
       //在这里我们传入作为Divider的Drawable对象
        mDrawable = context.getResources().getDrawable(resId);
    }    
    @Override
    public void onDrawOver(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;            
            final int bottom = top + mDrawable.getIntrinsicHeight();
            mDrawable.setBounds(left, top, right, bottom);
            mDrawable.draw(c);
        }
    }    @Override
    public void getItemOffsets(Rect outRect, int position, RecyclerView parent) {
        outRect.set(0, 0, 0, mDrawable.getIntrinsicWidth());
    }
}

在这里我写了一个shape来代替分割线:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle" >    
   <solid android:color="#000" />    
   <size android:height="2dp" />
</shape>

添加分割线的效果:

20150423123352203.png

如何添加点击事件 ##

在Adapter中设置自己OnItemClickListener以及OnItemLongClickListener 
在ViewHolder中公开Item的根布局View,之后在onBindViewHolder方法获得根布局View并设置点击的listener,调用自己设置的listener

1.首先在MyAdapter中创建自己的接口:

public interface OnItemClickListener {    
    public void onClick(View parent, int position);
}
public interface OnItemLongClickListener {    
    public boolean onLongClick(View parent, int position);
}

2.接着在ViewHolder中将根布局View公开:

public class ViewHolder extends RecyclerView.ViewHolder {        
    public TextView textView;        
    public View itemView;        
    public ViewHolder(View view) {            
        super(view);            
        // TODO Auto-generated constructor stub            
        itemView = view;            
        textView = (TextView) view.findViewById(R.id.item_text);          }    
}

3.最后在onBindViewHolder对itemView设置点击事件:

viewHolder.itemView.setOnClickListener(new OnClickListener() {            @Override            
    public void onClick(View v) {                
        // TODO Auto-generated method stub                
        if (onItemClickListener != null) {                    
            onItemClickListener.onClick(v, position);                
        }            
    }        
});
viewHolder.itemView.setOnLongClickListener(new OnLongClickListener() {     @Override            
     public boolean onLongClick(View v) {                
         // TODO Auto-generated method stub                
         if (onItemLongClickListener != null) {                    
             return onItemLongClickListener.onLongClick(v, position);          }                
         return false;            
     }        
});

如何判断是否滑动到达尾部或顶部

LinearLayoutManager提供了如下几个方法来帮助开发者获取屏幕上的顶部item和底部item: 
findFirstVisibleItemPosition() 
findFirstCompletelyVisibleItemPosition() 
findLastVisibleItemPosition() 
findLastCompletelyVisibleItemPosition()

这样我们就得到了思路:对RecyclerView设置滑动监听事件,在其中进行判断:

mRecyclerView.setOnScrollListener(new OnScrollListener() {    
    boolean isShowTop = false;    
    boolean isShowBottom = false; 
       
    @Override    
    public void onScrolled(int arg0, int arg1) {        
        // TODO Auto-generated method stub        
        if (mLayoutManager.findLastCompletelyVisibleItemPosition() == 99) {            
            if (!isShowTop) {                
                Toast.makeText(MainActivity.this, "滑动到底部",                        Toast.LENGTH_SHORT).show();            
            }            
            isShowTop = true;        
        } else {            
            isShowTop = false;        
        }        
        if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) {            
            if (!isShowBottom) {                
                Toast.makeText(MainActivity.this, "滑动到顶部",                        Toast.LENGTH_SHORT).show();            
            }            
            isShowBottom = true;        
        } else {            
            isShowBottom = false;       
        }    
    }    
    @Override    
    public void onScrollStateChanged(int arg0) {        
        // TODO Auto-generated method stub    
    }
});

来看一下效果:

20150423123535188.gif

添加或移除数据

RecyclerView.Adapter中提供了两个方法来做出添加数据或删除数据的调整: 
public final void notifyItemInserted(int position) 
public final void notifyItemRemoved(int position)

这样我们只需在自己的Adapter中提供添加或删除的方法,并在方法之中调用上述方法即可:

public void insert(String data, int position){        
    dataList.add(position, data);        
    notifyItemInserted(position);    
}    
public void remove(int position){        
    dataList.remove(position);        
    notifyItemRemoved(position);    
}

接下来我在Activity中对RecyclerView设置点击添加数据,长按删除数据;

adapter.setOnItemClickListener(new OnItemClickListener() {                @Override            
    public void onClick(View parent, int position) {               
        // TODO Auto-generated method stub                
        adapter.insert("Insert", position);            
    }        
});        
adapter.setOnItemLongClickListener(new OnItemLongClickListener() {        @Override            
    public boolean onLongClick(View parent, int position) {                   // TODO Auto-generated method stub                
        adapter.remove(position);                
        return true;            
    }        
});

来看一下效果吧:

20150423123813098.gif

ItemAnimator可以设置加载和移除时的动画,我们可以通过setItemAnimator方法设置,但目前只提供了DefaultItemAnimator。

源码下载

点击下载源码



用户评论