记得每一次在用ListView的时候,在Adapter中,总是需要我们自己去创建一个ViewHolder,去存储ListItem的布局,这么做的原因在于findViewById()是一个很耗时间的操作,所以我们需要一个静态的对象将layout过的控件给保存起来,下一次刷新这个item的时候,就不再需要调用findViewById去ViewTree中初始化控制,从而达到对ListView的优化效果。
而RecycleView则已经帮我们封闭好了这样一个ViewHolder的抽象类RecycleView.ViewHolder,而且是必须实现的一个接口,这说明在控制节省内存方面,RecycleView要比ListView做得要好,因为在ListView中,你不写ViewHolder也是可以的。
此外,ListView的设计是一个上下滑动的列表控制,而RecycleView则通过一个LayoutManager来实现多种布局的展现,包括纵向列表,横向Gallery,Grid布局,基于瀑布流等,可以说,之前通过ListView, GridView, ViewPager等实现的布局,现在用一个RecycleView就可以实现了。
再此外,现在的很多app,就算是使用ListView,也不仅仅是单纯地展现数据,都希望能够利用一些平滑的动画效果来提升用户体验,而RecycleView本身在对数据的增删上就添加了对动画的效果的的支持。
在RecyclerView中增加了以下的接口:
public final void notifyItemInserted(int position) {
mObservable.notifyItemRangeInserted(position, 1);
}
public final void notifyItemMoved(int fromPosition, int toPosition) {
mObservable.notifyItemMoved(fromPosition, toPosition);
}
public void setItemAnimator(ItemAnimator animator) {
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
mItemAnimator.setListener(null);
}
mItemAnimator = animator;
if (mItemAnimator != null) {
mItemAnimator.setListener(mItemAnimatorListener);
}
}
综合种种,个人觉得,是很有必要掌握一下如何使用RecycleView的。
RecycleView是Support-v7包中的组件,因此在Gradle中,我们要添加其对应的引用
dependencies {
...
compile 'com.android.support:recyclerview-v7:23.1.0'
...
}
在xml布局中,如下使用
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_widget" android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView android:id="@+id/order_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/normal_space" />
</android.support.v4.widget.SwipeRefreshLayout>
在Activity中,
private RecyclerView mOrderListView;
private LinearLayoutManager mLayoutManager;
private OrderListRecycleViewAdapter mOrderListAdapter;
mOrderListView = (RecyclerView) findViewById(R.id.order_list);
mLayoutManager = new LinearLayoutManager(this);
mOrderListView.setHasFixedSize(true);
mOrderListView.setLayoutManager(mLayoutManager);
mOrderListAdapter = new OrderListRecycleViewAdapter(this, mOrderList, this);
mOrderListView.setAdapter(mOrderListAdapter);
这里可看到分为几步:
目前SDK中提供了三种LayoutManager,分别为
- LinearLayoutManager
- GridLayoutManager
- StaggeredGridLayoutManager
使用不同的LayoutManager,分别如下:
mLayoutManager = new LinearLayoutManager(this)
mLayoutManager = new GridLayoutManager(this, 1, LinearLayoutManager.Vertical, false)
GridLayoutManager的构造有如下几种:
/** * Creates a vertical GridLayoutManager * * @param context Current context, will be used to access resources. * @param spanCount The number of columns in the grid */
public GridLayoutManager(Context context, int spanCount) {
super(context);
setSpanCount(spanCount);
}
/** * @param context Current context, will be used to access resources. * @param spanCount The number of columns or rows in the grid * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link * #VERTICAL}. * @param reverseLayout When set to true, layouts from end to start. */
public GridLayoutManager(Context context, int spanCount, int orientation,
boolean reverseLayout) {
super(context, orientation, reverseLayout);
setSpanCount(spanCount);
}
在这里,按照我们上述的声明,其实现的效果跟LinearLayout的效果是一致的,当SpanCount值大于1的时候,就能够以格式的效果展现,这种切换其实还是挺简单的,是不?
StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL);
看效果就已经能够实现简单的瀑布流了。
接下来还要对recycleView设置以下的方法:
设置hasFixedSize方法
调用此方法,可让RecycleView保持展现的item数目,在RecycleView的实现中会有一些优化。
声明Adapter,将调用RecycleView的setAdapter方法进行赋值。
到这里,除了去实现 Adapter之后,对RecycleView的初始化及使用,到此即可。
除此之外,我们还能够调用RecycleView的addItemDecoration方法和setItemAnimator方法来自定义item的分隔线及item的动画效果。
mOrderListView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
mOrderListView.setItemAnimator(new DefaultItemAnimator());
我们实现的Adapter必须继承于RecycleView.Adapter,如下
public class OrderListRecycleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
而需要我们去实现的方法,如下展示:
@Override
public int getItemViewType(int position) {
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (TYPE_ITEM == viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.order_list_item, parent, false);
return new OrderListViewHolder(view);
} else {
View view = LayoutInflater.from(mContext).inflate(R.layout.list_footer, parent, false);
return new OrderListFooterHolder(view);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof OrderListViewHolder) {
Order order = mData.get(position);
OrderListViewHolder itemHolder = (OrderListViewHolder) holder;
...
} else if (holder instanceof OrderListFooterHolder) {
OrderListFooterHolder footerHolder = (OrderListFooterHolder) holder;
...
}
}
@Override
public int getItemCount() {
return mData.size() + 1;
}
static class OrderListFooterHolder extends RecyclerView.ViewHolder {
TextView itemFooter;
public OrderListFooterHolder(View itemView) {
super(itemView);
itemFooter = (TextView) itemView.findViewById(R.id.item_footer);
}
}
static class OrderListViewHolder extends RecyclerView.ViewHolder {
....
public OrderListViewHolder(View itemView) {
super(itemView);
...
}
}
在上面这个Adapter中,其实做了几件事:
public int getItemViewType(int position)
根据getItemViewType返回我们要去加载的item布局,这一个方法的实现不是必须的,在这里只是因为需要去加载两个布局,所以就定义了两个ITEM_TYPE,如果就一个布局,这方法可以不实现。
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
如果有不同的viewType,我们则必须根据不同的viewType来从不同的item布局中,利用LayoutInflater来加载,并创建对应的ViewHolder,因此在这里,我们需要实现onCreateViewHolder方法,其会返回一个RecyclerView.ViewHolder对象。
static class OrderListFooterHolder extends RecyclerView.ViewHolder
static class OrderListViewHolder extends RecyclerView.ViewHolder
既然上一步返回了一个RecyclerView.ViewHolder对象,对应的,我们就要实现自己的ViewHolder,来存储对应的组件了,如上面的OrderListFootHolder和OrderListViewHolder。
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position)
有了ViewHolder之后,接下来就是要将ViewHolder和数据给绑定到一起来,则需要去调用OnBindViewHolder方法了,其参数一个为对应的ViewHolder,一个为对应的位置,通过此位置,去数据列表中获取对应的数据。
public int getItemCount()
最后,我们还要实现getItemCount方法,告知RecycleView,此Adapter到底要处理多少个对象。
至此,对RecycleView的基本使用就可是这样了。