SnapHelpter,相信很多人可能都不知道它或者没怎么关注过它,但是通过它实现的效果肯定都见过。比如短视频应用中切换视频时一划划一页的效果,这可不是ViewPager实现的啊,使用ViewPager实现的话成本太高,所以这类效果都是通过RecyclerVIew + SnapHelper来实现的,拿刚才讲的短视频切换效果来说,使用的就是RecyclerVIew和SnapHelper的子类PagerSnapHelper来实现的。
目录
一、SnapHelper初解
说了这些,那么SnapHelper到底是什么东西呢?见名思意,Snap,翻译成中文有‘移到某位置’的意思,那么SnapHelper可以理解为‘移到某位置的帮手’,而这个被移到某位置的东西显然就是RecyclerVIew中的Item。
public abstract class SnapHelper extends RecyclerView.OnFlingListener {
//....
@Nullable
public abstract int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager,
@NonNull View targetView);
@Nullable
public abstract View findSnapView(LayoutManager layoutManager);
public abstract int findTargetSnapPosition(LayoutManager layoutManager, int velocityX,int velocityY);
}
可以看到SnapHelper是一个抽象类,并继承了RecyclerView.OnFlingListener这个类,其中还包括三个抽象方法,我们通过实现这三个方法,就可以帮助RecyclerView移动item到‘某位置’。
为了更好理解SnapHelper的这三个方法,先说说RecyclerView.OnFlingListener这个类。
public abstract static class OnFlingListener {
/**
* 可用于实现自定义投掷行为
*
* @param velocityX X轴上的抛掷速度
* @param velocityY Y轴上的抛掷速度
*
* @return 如果处理了投掷,则为 true,否则为 false。
*/
public abstract boolean onFling(int velocityX, int velocityY);
}
这也是个抽象类,并且里面只有一个抽象方法,那这个类又是干啥的呢?我们都知道RecyclerView是可以滑动的,在我们手指离开屏幕后,RecyclerView还会继续顺着我们手指的方向再滑动一段距离,这个操作就是通过实现OnFlingListener接口来做到的。
SnapHelper继承了OnFlingListener实现了onFling方法,并在调用attachToRecyclerView()方法的时候将OnFlingListener设置给了RecyclerView。
public void attachToRecyclerView(@Nullable RecyclerView recyclerView)
throws IllegalStateException {
if (mRecyclerView == recyclerView) {
return; // nothing to do
}
if (mRecyclerView != null) {
destroyCallbacks();
}
mRecyclerView = recyclerView;
if (mRecyclerView != null) {
setupCallbacks();
mGravityScroller = new Scroller(mRecyclerView.getContext(),
new DecelerateInterpolator());
snapToTargetExistingView();
}
}
/**
* Called when an instance of a {@link RecyclerView} is attached.
*/
private void setupCallbacks() throws IllegalStateException {
if (mRecyclerView.getOnFlingListener() != null) {
throw new IllegalStateException("An instance of OnFlingListener already set.");
}
mRecyclerView.addOnScrollListener(mScrollListener);
mRecyclerView.setOnFlingListener(this);
}
二、三个方法
接着我们继续看SnapHelper中的三个抽象方法。
1、calculateDistanceToFinalSnap()
/**
* 计算将目标item移动到最终位置所需距离
*
* @param layoutManager
* @param targetView 需要被移动的item
*
* @return 输出坐标将结果,out[0] 是水平轴上的距离,out[1] 是垂直轴上的距离。
*/
@SuppressWarnings("WeakerAccess")
@Nullable
public abstract int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager,
@NonNull View targetView);public abstract int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,@NonNull View targetView);
这个方法是SnapHelper中另外两个抽象方法findSnapView()和findTargetSnapPosition()的下游方法,其参数中的targetView就是这两个方法提供的
通过findSnapView()提供
void snapToTargetExistingView() {
/***/
View snapView = findSnapView(layoutManager);
if (snapView == null) {
return;
}
int[] snapDistance = calculateDistanceToFinalSnap(layoutManager, snapView);
if (snapDistance[0] != 0 || snapDistance[1] != 0) {
mRecyclerView.smoothScrollBy(snapDistance[0], snapDistance[1]);
}
}
通过findTargetSnapPosition()提供
private boolean snapFromFling

本文详细解析了SnapHelper的工作原理及其实现方式,包括calculateDistanceToFinalSnap、findSnapView和findTargetSnapPosition三个核心方法,并提供了一个自定义SnapHelper的实例。
最低0.47元/天 解锁文章
2036

被折叠的 条评论
为什么被折叠?



