您的位置:首页 > 移动开发 > Android开发

Android开发--RecyclerView使用,看AndroidL新特性

2015-04-23 12:40 543 查看
在去年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的基本用法:



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 viewType) {
// 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>


添加分割线的效果:



如何添加点击事件

在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

}
});


来看一下效果:



添加或移除数据

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;
}
});


来看一下效果吧:



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

源码下载

点击下载源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 控件 androidL