SnapHelper

一、了解SnapHelper

其实SnapHelper是对RecyclerView的一种拓展。

SnapHelper的实现原理是监听RecyclerView.OnFlingListener中的onFling接口。LinearSnapHelper是抽象类SnapHelper的具体实现。

通过LinearSnapHelper,可以使RecyclerView实现类似ViewPager的功能,无论怎么滑动最终停留在某页正中间。

二、实现效果

1.自带LinearSnapHelper实现

可以将某页自动居中。

LinearSnapHelper  mLinearSnapHelper=new LinearSnapHelper();

mLinearSnapHelper.attachToRecyclerView(mRecyclerView);

2.自定义SnapHelper实现

比如,左对齐。

SnapHelper是一个抽象类,直接继承需要实现的三个方法:

  1. 当拖拽或滑动结束时会回调该方法,返回一个out = int[2],out[0]x轴,out[1] y轴 ,这个值就是需要修正的你需要的位置的偏移量
public abstract int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager, @NonNull View targetView);
  1. 上面方法有一个targetView吧 就是这个方法返回的
public abstract View findSnapView(LayoutManager layoutManager);
  1. 用于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

你可能感兴趣的:(SnapHelper)