关于 LayoutManager 的使用有下面一些常见的 API(有些在 LayoutManager 实现的子类中)
canScrollHorizontally();//能否横向滚动 canScrollVertically();//能否纵向滚动 scrollToPosition(int position);//滚动到指定位置 setOrientation(int orientation);//设置滚动的方向 getOrientation();//获取滚动方向 findViewByPosition(int position);//获取指定位置的Item View findFirstCompletelyVisibleItemPosition();//获取第一个完全可见的Item位置 findFirstVisibleItemPosition();//获取第一个可见Item的位置 findLastCompletelyVisibleItemPosition();//获取最后一个完全可见的Item位置 findLastVisibleItemPosition();//获取最后一个可见Item的位置上面仅仅是列出一些常用的 API 而已,更多的 API 可以查看官方文档,通常你想用 RecyclerView 实现某种效果,例如指定滚动到某个 Item 位置,但是你在 RecyclerView 中又找不到可以调用的 API 时,就可以跑到 LayoutManager 的文档去看看,基本都在那里。
另外还有一点关于瀑布流布局效果 StaggeredGridLayoutManager 想说的,看到网上有些文章写的示例代码,在设置了 StaggeredGridLayoutManager 后仍要去 Adapter 中动态设置 View 的高度,才能实现瀑布流,这种做法是完全错误的,之所以 StaggeredGridLayoutManager 的瀑布流效果出不来,基本是 item 布局的 xml 问题以及数据问题导致。如果要在 Adapter 中设置 View 的高度,则完全违背了 LayoutManager 的设计理念了。
这里我们简单分析LinearLayoutManager的实现。
对于LinearLayoutManager来说,比较重要的几个方法有:
onLayoutChildren(): 对RecyclerView进行布局的入口方法。
fill(): 负责填充RecyclerView。
scrollVerticallyBy():根据手指的移动滑动一定距离,并调用fill()填充。
canScrollVertically()或canScrollHorizontally(): 判断是否支持纵向滑动或横向滑动。
onLayoutChildren()的核心实现如下:
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { detachAndScrapAttachedViews(recycler); //将原来所有的Item View全部放到Recycler的Scrap Heap或Recycle Pool fill(recycler, mLayoutState, state, false); //填充现在所有的Item View }RecyclerView的回收机制有个重要的概念,即将回收站分为Scrap Heap和Recycle Pool,其中Scrap Heap的元素可以被直接复用,而不需要调用onBindViewHolder()。detachAndScrapAttachedViews()会根据情况,将原来的Item View放入Scrap Heap或Recycle Pool,从而在复用时提升效率。
fill()是对剩余空间不断地调用layoutChunk(),直到填充完为止。layoutChunk()的核心实现如下:
public void layoutChunk() { View view = layoutState.next(recycler); //调用了getViewForPosition() addView(view); //加入View measureChildWithMargins(view, 0, 0); //计算View的大小 layoutDecoratedWithMargins(view, left, top, right, bottom); //布局View }其中next()调用了getViewForPosition(currentPosition),该方法是从RecyclerView的回收机制实现类Recycler中获取合适的View,在后文的回收机制中会介绍该方法的具体实现。
如果要自定义LayoutManager,可以参考:
创建一个 RecyclerView LayoutManager – Part 1
创建一个 RecyclerView LayoutManager – Part 2
创建一个 RecyclerView LayoutManager – Part 3
Adapter适配器Adapter的使用方式前面已经介绍了,功能就是为RecyclerView提供数据,这里主要介绍万能适配器的实现。其实万能适配器的概念在ListView就已经存在了,即base-adapter-helper。
这里我们只针对RecyclerView,聊聊万能适配器出现的原因。为了创建一个RecyclerView的Adapter,每次我们都需要去做重复劳动,包括重写onCreateViewHolder(),getItemCount()、创建ViewHolder,并且实现过程大同小异,因此万能适配器出现了。
万能适配器这里讲解下万能适配器的实现思路。
我们通过public abstract class QuickAdapter<T> extends RecyclerView.Adapter<QuickAdapter.VH>定义万能适配器QuickAdapter类,T是列表数据中每个元素的类型,QuickAdapter.VH是QuickAdapter的ViewHolder实现类,称为万能ViewHolder。
首先介绍QuickAdapter.VH的实现:
static class VH extends RecyclerView.ViewHolder{ private SparseArray<View> mViews; private View mConvertView; private VH(View v){ super(v); mConvertView = v; mViews = new SparseArray<>(); } public static VH get(ViewGroup parent, int layoutId){ View convertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); return new VH(convertView); } public <T extends View> T getView(int id){ View v = mViews.get(id); if(v == null){ v = mConvertView.findViewById(id); mViews.put(id, v); } return (T)v; } public void setText(int id, String value){ TextView view = getView(id); view.setText(value); } }