RecyclerView 作为一个列表滑动控件,我们都知道它既可以横向滑动,也可以竖直滑动,可以实现线性布局管理,瀑布流布局管理,还有 GridView 布局管理。其实我们可以控制其 Item 的停留位置,并使其实现画廊效果。如果大家熟悉 SnapHelper 的话,估计大家就都会了。
SnapHelper 的实现原理就是是监听 RecyclerView.OnFlingListener 中的 onFling 接口。support library 中只提供了一个继承类 LinearSnapHelper ,LinearSnapHelper 是抽象类 SnapHelper 的具体实现。
通过 LinearSnapHelper,我们就可以使 RecyclerView 实现类似 ViewPager 的功能,无论怎么滑动最终都会停留在列表页面正中间。
SnapHelper 和 ViewPager 的区别就是 ViewPager 一次只能滑动一页,而 RecyclerView + SnapHelper 的方式可以实现一次滑动好几页。
效果如下:
使用 SnapHelper 配合 RecyclerView 实现控制 Item 位置居中显示,非常简单,官方默认提供的 LinearSnapHelper 就是居中的,我们直接使用即可。
代码如下:
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); recyclerView.setLayoutManager(linearLayoutManager); new LinearSnapHelper().attachToRecyclerView(recyclerView);
官方提供的默认是居中显示,其实我们也可以自定义,比如:靠左显示,让可见的第一个 Item 居左显示。
自定义 SnapHelper ,一般需要实现两个方法:
public classCustomSnapHelperextendsLinearSnapHelper{ private OrientationHelper mHorizontalHelper; @Override public int[] calculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView) { int[] out = new int[2]; //判断支持水平滚动,修改水平方向的位置,是修改的out[0]的值 if (layoutManager.canScrollHorizontally()) { out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager)); } else { out[0] = 0; } return out; } privateintdistanceToStart(View targetView, OrientationHelper helper){ return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding(); } @Override publicViewfindSnapView(RecyclerView.LayoutManager layoutManager){ return findStartView(layoutManager, getHorizontalHelper(layoutManager)); } privateViewfindStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) { if (layoutManager instanceof LinearLayoutManager) { int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); if (firstChild == RecyclerView.NO_POSITION) { return null; } //这行的作用是如果是最后一个,翻到最后一条,解决显示不全的问题 if (lastChild == layoutManager.getItemCount() - 1) { return layoutManager.findViewByPosition(lastChild); } View child = layoutManager.findViewByPosition(firstChild); //获取偏左显示的Item if (helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2 && helper.getDecoratedEnd(child) > 0) { return child; } else { return layoutManager.findViewByPosition(firstChild + 1); } } return super.findSnapView(layoutManager); } privateOrientationHelpergetHorizontalHelper( RecyclerView.LayoutManager layoutManager) { if (mHorizontalHelper == null) { mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); } return mHorizontalHelper; } }
调用自定义的 SnapHelper 代码如下,配合 RecyclerView:
CustomSnapHelper mMySnapHelper = new CustomSnapHelper(); mMySnapHelper.attachToRecyclerView(rv);
最后,其实垂直方向也可以实现哦,大家可以尝试一下垂直方向的使用方式是不是非常简单。
代码 Demo 地址: https://github.com/loonggg/SnapHelperDemo