我们都知道RecyclerView可以通过将LayoutManager设置为StaggeredGridLayoutManager来实现瀑布流的效果。默认的还有LinearLayoutManager用于实现线性布局,GridLayoutManager用于实现网格布局。
然而RecyclerView可以做的不仅限于此,通过重写LayoutManager我们可以按自己的意愿实现更为复杂的效果。而且将控件与其显示效果解耦之后我们就可以动态的改变其显示效果。
设想有这么一个界面,以列表形式展示了一系列的数据,点击一个按钮后以网格形势显示另一组数据。传统的做法可能是在同一布局下设置了一个listview和一个gridview然后通过按钮点击事件切换他们的visiblity属性。而如果使用recyclerview的话你只需通过setAdapter方法改变数据,setLayoutManager方法改变样式即可,这样不仅简化了布局也实现了逻辑上的简洁。
下面我们就来介绍怎么通过重写一个LayoutManager来实现一个弧形的recycylerview以及另一个会随着滚动在指定位置缩放的recyclerview。并实现类似viewpager的回弹效果。
弧形
缩放
通常重写一个LayoutManager可以分为以下几个步骤
指定默认的LayoutParams
测量并记录每个item的信息
回收以及放置各个item
处理滚动
指定默认的 LayoutParams
当你继承LayoutManager之后,有一个必须重写的方法
generateDefaultLayoutParams()
这个方法指定了每一个子view默认的LayoutParams,并且这个LayoutParams会在你调用getViewForPosition()返回子view前应用到这个子view。
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
测量并记录每个 item 的信息
接下来我们需要重写onLayoutChildren()这个方法。这是LayoutManager的主要入口,他会在初始化布局以及adapter数据发生改变(或更换adapter)的时候调用。所以我们在这个方法中对我们的item进行测量以及初始化。
在贴代码前有必要先提一下,recycler有两种缓存的机制,scrap heap 以及recycle pool。相比之下scrap heap更轻量一点,他会直接将当前的view缓存而不通过adapter,当一个view被detach之后就会暂存进scrap heap。而recycle pool所存储的view,我们一般认为里面存的是错误的数据(这个view之后需要拿出来重用显示别的位置的数据),所以这里面的view会被传给adapter进行数据的重新绑定,一般,我们将子view从其parent view中remove之后会将其存入recycler pool中。
当界面上我们需要显示一个新的view时,recycler会先检查scrap heap中position相匹配的view,如果有,则直接返回,如果没有recycler会从recycler pool中取一个合适的view,将其传递给adapter,然后调用adapter的bindViewHolder()方法,绑定数据之后将其返回。
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)