一、了解SnapHelper
其实SnapHelper是对RecyclerView的一种拓展。
SnapHelper的实现原理是监听RecyclerView.OnFlingListener中的onFling接口。LinearSnapHelper是抽象类SnapHelper的具体实现。
通过LinearSnapHelper,可以使RecyclerView实现类似ViewPager的功能,无论怎么滑动最终停留在某页正中间。
二、实现效果
1.自带LinearSnapHelper实现
可以将某页自动居中。
LinearSnapHelper mLinearSnapHelper=new LinearSnapHelper();
mLinearSnapHelper.attachToRecyclerView(mRecyclerView);
2.自定义SnapHelper实现
比如,左对齐。
SnapHelper是一个抽象类,直接继承需要实现的三个方法:
- 当拖拽或滑动结束时会回调该方法,返回一个out = int[2],out[0]x轴,out[1] y轴 ,这个值就是需要修正的你需要的位置的偏移量
public abstract int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager, @NonNull View targetView);
- 上面方法有一个targetView吧 就是这个方法返回的
public abstract View findSnapView(LayoutManager layoutManager);
- 用于Fling,根据速度返回你要滑到的position
public abstract int findTargetSnapPosition(LayoutManager layoutManager, int velocityX, int velocityY);
我们不直接继承SnapHelper,而是继承他的实现类LinearSnapHelper
public class MySnapHelper extends LinearSnapHelper {
privateOrientationHelper mHorizontalHelper;
@Nullable
@Override
public int[] calculateDistanceToFinalSnap (RecyclerView.LayoutManager layoutManager, View targetView) {
int[] out =newint[2];
if(layoutManager.canScrollHorizontally()) {
out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager));
}else{
out[0] =0;
}return out;
}
private int distanceToStart(View targetView, OrientationHelper helper) {
return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
}
@Nullable
@Override public View findSnapView(RecyclerView.LayoutManager layoutManager) {
return findStartView(layoutManager, getHorizontalHelper(layoutManager));
}
private View findStartView(RecyclerView.LayoutManager layoutManager,OrientationHelper helper) {
if(layoutManagerinstanceofLinearLayoutManager) {
intfirstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
intlastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
if(firstChild == RecyclerView.NO_POSITION) {
return null;
} if(lastChild == layoutManager.getItemCount() -1) {
return layoutManager.findViewByPosition(lastChild);
}
View child = layoutManager.findViewByPosition(firstChild);
if(helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) /2&& helper.getDecoratedEnd(child) >0) {
return child;
} else{
return layoutManager.findViewByPosition(firstChild +1);
}
}
return super.findSnapView(layoutManager);
}
private OrientationHelpergetHorizontalHelper(
@NonNull
RecyclerView.LayoutManager layoutManager) {
if(mHorizontalHelper ==null) {
mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
} return mHorizontalHelper;
}
}
这里有几点需要特别注意一下,
第11~24行:我们只考虑横向左对齐,所以只要处理out[0]的值,distanceToStart()方法返回修正的偏移量。
第41~43行:这是为了解决当翻到最后一页的时候,最后一个Item不能完整显示的问题(不信,你可以注释了试试就知道啦)。
if(lastChild == layoutManager.getItemCount() -1) {
returnlayoutManager.findViewByPosition(lastChild);
}
第47~52行:得到此时需要左对齐显示的条目
if(helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) /2
&& helper.getDecoratedEnd(child) >0) {
return child;
} else{
return la youtManager.findViewByPosition(firstChild +1);
}
最后只要用上我们自己的SnapHelper,就可以轻松搞定了。
MySnapHelper mMySnapHelper=new MySnapHelper();
mMySnapHelper.attachToRecyclerView(mRecyclerView);
已经实现的库:https://github.com/rubensousa/RecyclerViewSnap
参考文章:http://blog.csdn.net/whitley_gong/article/details/52421215