Google最新发布的support recyclerview包更新到24.2.0,这次来聊聊RecyclerView的新特性和SnapHelper的关系。
一句话介绍SnapHelper: SnapHelper是RecyclerView功能的一种拓展,使RecyclerView滑动行为类似ViewPager,无论怎么滑动最终停留在某页正中间。ViewPager一次只能滑动一页,RecyclerView+SnapHelper方式可以一次滑动好几页,且最终都停留在某页正中间。非常实用和酷炫。
SnapHelper的实现原理是监听RecyclerView.OnFlingListener中的onFling接口。LinearSnapHelper
是抽象类SnapHelper的具体实现。
上面的效果只需下面几行代码即可。重点在于new LinearSnapHelper().attachToRecyclerView(recyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); recyclerView.setLayoutManager(linearLayoutManager); new LinearSnapHelper().attachToRecyclerView(recyclerView);
接下来具体分析LinearSnapHelper是怎么实现类似ViewPager的功能的
attachToRecyclerView,居中处理分析
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException { ... snapToTargetExistingView(); ... } /** * 1. 找到居中显示的View * 2. 计算view离当前的位置距离, 调用mRecyclerView.smoothScrollBy使其居中 */ private void snapToTargetExistingView() { View snapView = findSnapView(layoutManager); int[] snapDistance = calculateDistanceToFinalSnap(layoutManager, snapView); if (snapDistance[0] != 0 || snapDistance[1] != 0) { mRecyclerView.smoothScrollBy(snapDistance[0], snapDistance[1]); } } /** * 1. 找到当前RecyclerView的居中位置center * 2. 循环遍历子节点,找出子节点居中位置最接近center的视图,及SnapView */ public View findSnapView(RecyclerView.LayoutManager layoutManager) { ... } /** * 计算到targetView要移动的距离 */ @Override public int[] calculateDistanceToFinalSnap( @NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) { ... }
RecyclerView.OnFling,滑动后停止到居中位置分析
SnapHelper extends RecyclerView.OnFlingListener,重载onFling函数
public boolean onFling(int velocityX, int velocityY) { LayoutManager layoutManager = mRecyclerView.getLayoutManager(); if (layoutManager == null) { return false; } RecyclerView.Adapter adapter = mRecyclerView.getAdapter(); if (adapter == null) { return false; } int minFlingVelocity = mRecyclerView.getMinFlingVelocity(); return (Math.abs(velocityY) > minFlingVelocity || Math.abs(velocityX) > minFlingVelocity) && snapFromFling(layoutManager, velocityX, velocityY); } /** * 同样的套路,先根据移动速度确定最终位置,然后startSmoothScroll */ private boolean snapFromFling(@NonNull LayoutManager layoutManager, int velocityX, int velocityY) { ... int targetPosition = findTargetSnapPosition(layoutManager, velocityX, velocityY); if (targetPosition == RecyclerView.NO_POSITION) { return false; } smoothScroller.setTargetPosition(targetPosition); layoutManager.startSmoothScroll(smoothScroller); return true; }
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦