前言
RecyclerView已经出来好一段时间了,对于新接触Android的学员来说大多数使用的是ListView与GridView,对于RecyclerView的使用可能都不是很熟悉,相信这片文章能很好的带你进去RecyclerView的大门,快速了解与掌握新技术。
添加依赖
大家使用ListView与GridView只要在xml中引用就可以了,没错RecyclerView也是一样,但在引用前要先添加依赖,在项目的app目录下的build.gradl的dependencies中添加:
compile 'com.android.support:recyclerview-v7:23.2.0'
完了之后别忘了Sync Now
Adapter变化
既然要有ListView与GridView的效果自然不能少了adapter,而RecyclerView的adapter主要有两个重大的变化,原来adapter中的getView()方法取消了,替换成了onCreateViewHolder()与onBindViewHolder()。其实就是分成了两部分,一部分创建视图另一部分绑定数据,是不是感觉层次更清晰了呢,下面主要介绍之两大方法的使用。
onCreateViewHolder
说白了这个方法就是创建视图,在创建之前要创建个ViewHolder相信在原来的adapter中应该有使用过吧.这里继承RecyclerView.ViewHolder
public static class NormalViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.item_tv)
TextView itemTv;
public NormalViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
然后在onCreateViewHolder中调用:
@Override
public NormalViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new NormalViewHolder(mLayoutInflater.inflate(R.layout.item_text, parent, false));
}
onBindViewHolder
视图创建完毕就是简单的绑定了,使用holder对控件进行绑定设置数据:
@Override
public void onBindViewHolder(NormalViewHolder holder, int position) {
holder.itemTv.setText((CharSequence) mListData.get(position));
}
OK了,是不是感觉很简单呢?是的就是这么简单,至于设置adapter就不说了相信之后的步骤大家都会了。
setLayoutManager
你是不是想说如何设置显示的方式是ListView与GridView,这个其实更加简单只需一句代码,setLayoutManager()即可:
switch (type) {
case App.LINEAR_LAYOUT:
//ListView
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
break;
case App.GRID_LAYOUT:
//GridView
gridLayoutManager = new GridLayoutManager(getActivity(),3);
recyclerView.setLayoutManager(gridLayoutManager);
break;
case App.STAGGERED_GRID_LAYOUT:
//Can customize the waterfall flow
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));
break;
default:
break;
}
设置了显示的方式后再setAdapter()即可,效果图还是放到最后一起显示吧
ListView与GridView嵌套效果
如果要实现首尾是ListView布局效果,中间的GridView效果,我们可以使用RecyclerView.Adapter提供的getItemViewType(int position)方法,注意这里与ListView的adapter不同只有这一个方法,没有getViewTypeCount() 方法,我们可以通过首尾要显示的行数来控制显示的布局
@Override
public int getItemViewType(int position) {
mHeadCount = getHeadCount();
mContentCount = getContentCount();
mBottomCount = mHeadCount + mContentCount;
if (mHeadCount > position) {
return App.LINEAR_LAYOUT;//ListView
} else if (mBottomCount <= position) {
return App.STAGGERED_GRID_LAYOUT;//Can customize the waterfall flow
} else {
return App.GRID_LAYOUT;//GridView
}
}
根据不同的viewtype返回不同的布局
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case App.LINEAR_LAYOUT:
return onCreateHeadViewHolder(parent);
case App.GRID_LAYOUT:
return onCreateContentViewHolder(parent);
case App.STAGGERED_GRID_LAYOUT:
return onCreateBottomViewHolder(parent);
default:
return null;
}
}
RecyclerView动画
RecyclerView的adapter提供了一些简单的动画实现,下面是一部分:
- notifyItemRemoved(int position)
- notifyItemInserted(int position)
- notifyItemChanged(int position)
- notifyItemRangeChanged(int positionStart,int itemCount)
只要在数据改变时通过adapter调用就行:
@OnClick(R.id.item_tv)
public void onClick() {
if (getLayoutPosition() != 1) {
animationAdapter.mListData.add("add"+getLayoutPosition());
animationAdapter.notifyItemInserted(getLayoutPosition());
} else {
animationAdapter.mListData.remove(getLayoutPosition());
animationAdapter.notifyItemRemoved(getLayoutPosition());
}
}
使用recyclerView的setItemAnimator()可以设置动画:
recyclerView.setItemAnimator(new DefaultItemAnimator());
当然你也可以实现自己的动画,只要extends ItemAnimator重写几个方法,这里就不展开了,读者可以自己去试试。
RecyclerView的CursorAdapter
讲到这里了你可以能会认为CursorAdapter也是跟原来的差不多,但我要说的是RecyclerView并没有提供有关与CursorAdapter的操作。所以当我们要使用CursorAdapter时要怎么办呢?我们只能自己实现一个CursorAdapter的抽象类,是不是感觉头痛,这一点看起来确实有点麻烦,但是我告诉你们实现也是很简单的一件事,为什么这么说呢,因为我们只要仿造ListView的CursorAdapter就可以了。
CursorFilter
这个是Cursor的过滤器,我们无需做什么,找到ListView的CursorFilter复制就可以了。代码没什么贴的,都是源码,自己可以去查看.
RecyclerBaseCursorAdapter
这个抽象类大部分都是与ListView的CursorAdapter相同,只是有几个地方需要特别提醒下
- 原来的有notifyDataSetInvalidated()方法,但RecyclerView没有提供该方法,我们可以使用notifyDataSetChanged()替代
- 原来的hasStableIds() 方法也没用,我们也可以使用setHasStableIds(true)设置为ture来实现相同的效果
- 原来的getView()方法要替换成onBindViewHolder()方法
void init(Context context, Cursor c, int flags) {
boolean cursorPresent = c != null;
mCursor = c;
mDataValid = cursorPresent;
mContext = context;
mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
mChangeObserver = new ChangeObserver();
mDataSetObserver = new MyDataSetObserver();
} else {
mChangeObserver = null;
mDataSetObserver = null;
}
if (cursorPresent) {
if (mChangeObserver != null) c.registerContentObserver(mChangeObserver);
if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver);
}
//should set true to init
setHasStableIds(true);
}
@Override
public void onInvalidated() {
mDataValid = false;
// notifyDataSetInvalidated();
//there is no notifyDataSetInvalidated method we should use notifyDataSetChanged method;
notifyDataSetChanged();
}
基本上主要的就是这些了,更多详情可以查看后面的Demo链接,最后使用都相同的套路,继承该抽象类,相信应该没有问题。
效果图
结语
最后感谢大家的阅读,有不足的地方欢迎指出。
源码地址链接:https://github.com/idisfkj/Re...
博客文章链接:https://idisfkj.github.io/201...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。