why recycleview ? 是ListView的更高度定制版,当你需要高效的展示大量数据时候,动态改变列表样式的时候,就用这个。
当然,如果只是动态展示数据,listview也可以做到,用它替代listview的原因有几个:
- 简介中提到的它封装了viewholder的回收复用。
- RecyclerView使用布局管理器管理子view的位置(目前尚只提供了LinearLayoutManager),你能够使用复杂的布局来展示一个列表 ,再不用拘泥于ListView的线性展示方式,如果之后提供其他custom LayoutManager的支持。
StaggeredGridLayoutManager mStaggeredGridLayoutManager =
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
//表示两列,并且是竖直方向的瀑布流
mRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);在布局上支持三种
StaggeredGridLayoutManager(错列的)
,GridLayoutManager
LinearLayoutManager
。 - 自带了ItemAnimation,可以设置加载和移除时的动画,方便做出各种动态浏览的效果。
- 分开的view
我们平时用listview的时候,adapter一般这么写的if (convertView == null) { holder = new ViewHolder(); LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); convertView = inflater.inflate( R.layout.list_device_binding, parent, false); holder.deviceImage = (ImageView) convertView .findViewById(R.id.bluetoothDeviceImage); holder.deviceName = (TextView) convertView .findViewById(R.id.bluetoothDeviceName); holder.deviceType = (TextView) convertView .findViewById(R.id.bluetoothDeviceType); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); }
但是,到了这里,他把他分隔开了,如下
@Override public A onCreateViewHolder(ViewGroup parent, int viewType) { final View view = LayoutInflater.from(mContext). inflate(R.layout.listitem_track_history, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(A holder, int position) { Data da=getData(position); holder.tvDate.setText(da.getDate()); }
我们就再也不用像以前那样写了.
- 相对简单
我们看下Listview他背后的继承关系public class ListView extends AbsListView public abstract class AbsListView extends AdapterView<ListAdapter> public abstract class AdapterView<T extends Adapter> extends ViewGroup
三重继承,内容还挺多的,不是直接继承ViewGroup,而相反的RecycleView却是直接继承自ViewGroup的。
缺点:
目前相对于我们对listview经常用到的方法,有下面两个问题:
1. 不能简单的加头和尾 header、footer
2. 不能简单的设置子item的点击事件。
具体的解决方案如下
- 不能简单的添加Head和Footer
在使用过程中,你发现你要添加头和尾不是很容易,因为没有直接的addHead和addFoot的方法了,不过这里有一个tumblr开源的库,可以让你实现这个功能,核心的代码如下@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { if (isHeader(viewType)) { int whichHeader = Math.abs(viewType - HEADER_VIEW_TYPE); View headerView = mHeaders.get(whichHeader); return new RecyclerView.ViewHolder(headerView) { }; } else if (isFooter(viewType)) { int whichFooter = Math.abs(viewType - FOOTER_VIEW_TYPE); View footerView = mFooters.get(whichFooter); return new RecyclerView.ViewHolder(footerView) { }; } else { return mBase.onCreateViewHolder(viewGroup, viewType); } } @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { if (position < mHeaders.size()) { // Headers don‘t need anything special } else if (position < mHeaders.size() + mBase.getItemCount()) { // This is a real position, not a header or footer. Bind it. mBase.onBindViewHolder(viewHolder, position - mHeaders.size()); } else { // Footers don‘t need anything special } } @Override public int getItemViewType(int position) { if (position < mHeaders.size()) { return HEADER_VIEW_TYPE + position; } else if (position < (mHeaders.size() + mBase.getItemCount())) { return mBase.getItemViewType(position - mHeaders.size()); } else { return FOOTER_VIEW_TYPE + position - mHeaders.size() - mBase.getItemCount(); }
- 不能简单的添加点击事件
onListItemClickListener
我们在使用listview设置子item的点击事件的时候,只需要像下面这么写listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { User user= parent.getItemAtPosition(position); } });
但是,如果你使用这个RecycleView,会发现没有这个接口了。RecyclerView不再负责Item视图的布局及显示,所以RecyclerView也没有为Item开放OnItemClick等点击事件,这就需要我们自己实现,实现的方法像看到有三种,目前下面这种比较合理,所以推荐如下写法
- 让你的viewholder实现onClickListener,然后在这个方法里面回调我们自己写的接口。
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private TextView tvDate; public ViewHolder(View itemView) { super(itemView); tvDate = (TextView) itemView.findViewById(R.id.tv_date); itemView.setOnClickListener(this); } @Override public void onClick(View v) { if(listener!=null){ listener.onItemClick(getPosition(),mList.get(getPosition())); } } } //我们回调的自定义接口 public interface onListItemClickListener{ void onItemClick(int position,TrackHistory mTrackHistory); }
- 接着在你的
Adapter
里面加多个set方法,里面设置回调接口public void setOnItemClickListener(onListItemClickListener listener){ this.listener = listener; }
- 让你的viewholder实现onClickListener,然后在这个方法里面回调我们自己写的接口。
小结
从上面的简单比较,对于我而言如果不是最求很高的效率,我不选择用这个,确实有点不方便了