打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
横向居中的RecyclerView

首先先要配置compile “com.android.support:recyclerview-v7:24.2.0” 
SnapHelper LinearSnapHelper,在版本大于24.2.0中才支持 
效果图如图所示

SnapHelper helper = new LinearSnapHelper(); 
helper.attachToRecyclerView(mRlRecommends);


        LinearSnapHelper snapHelper = new LinearSnapHelper() {            @Override            public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {                View centerView = findSnapView(layoutManager);                if (centerView == null)                    return RecyclerView.NO_POSITION;                int position = layoutManager.getPosition(centerView);                int targetPosition = -1;                if (layoutManager.canScrollHorizontally()) {                    if (velocityX < 0) {                        targetPosition = position - 1;                    } else {                        targetPosition = position + 1;                    }                }                if (layoutManager.canScrollVertically()) {                    if (velocityY < 0) {                        targetPosition = position - 1;                    } else {                        targetPosition = position + 1;                    }                }                final int firstItem = 0;                final int lastItem = layoutManager.getItemCount() - 1;                targetPosition = Math.min(lastItem, Math.max(targetPosition, firstItem));                return targetPosition;            }        };        snapHelper.attachToRecyclerView(mRlRecommends);

二,使用完这个方法我们会发现一个小问题,横向时,第一个和最后一个在滑动过后, 
当设置点击事件后没有响应了,首先 debug 了 内层 RecyclerView 的 onInterceptTouchEvent, 
发现这个时候 return 为 true, 而且这时 RecyclerView 的状态 不是 SCROLL_STATE_IDLE,而是 SCROLL_STATE_SETTLING ,看 RecyclerView 的源码

if (mScrollState == SCROLL_STATE_SETTLING) { 
getParent().requestDisallowInterceptTouchEvent(true); 
setScrollState(SCROLL_STATE_DRAGGING); 

… 
return mScrollState == SCROLL_STATE_DRAGGING; 
因此这个时候 RecyclerView 会拦截事件。 
事实上导致 RecyclerView 的状态 为 SCROLL_STATE_SETTLING 是因为 LinearSnapHelper。 
LinearSnapHelper 原理是监听 RecyclerView 的滚动状态,一旦处于RecyclerView.SCROLL_STATE_IDLE (当然还有 Fling 的情况,这里先不看) 就会计算得到要处于中心的 Item View,然后在计算需要滚动的距离。 
处于中心这个点很重要,细心的读者可能会发现第一个 Item 并不会处于中心的,那么这个时候 LinearSnapHelper 会怎么处理呢? 
LinearSnapHelper 会根据 calculateDistanceToFinalSnap 得到的距离 利用 RecyclerView 的 smoothScrollBy 来滚动,而这个时候第一个 Item 永远都滚动不到中心的位置,于是不停的 ScrollBy 也就导致 状态 为 SCROLL_STATE_SETTLING。

知道原因后就好办了, 重写 calculateDistanceToFinalSnap 修正距离就可以了 
用以下的 FixLinearSnapHelper 代替 LinearSnapHelper 就可以

public class MySnapHelper extends LinearSnapHelper {

private OrientationHelper mVerticalHelper;private OrientationHelper mHorizontalHelper;private RecyclerView mRecyclerView;@Overridepublic int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,                                          @NonNull View targetView) {    int[] out = new int[2];    if (layoutManager.canScrollHorizontally()) {        out[0] = distanceToCenter(targetView, getHorizontalHelper(layoutManager));    } else {        out[0] = 0;    }    if (layoutManager.canScrollVertically()) {        out[1] = distanceToCenter(targetView, getVerticalHelper(layoutManager));    } else {        out[1] = 0;    }    return out;}@Overridepublic void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {    this.mRecyclerView = recyclerView;    super.attachToRecyclerView(recyclerView);}private int distanceToCenter(View targetView, OrientationHelper helper) {    //如果已经滚动到尽头 并且判断是否是第一个item或者是最后一个,直接返回0,不用多余的滚动了    if ((helper.getDecoratedStart(targetView) == 0 && mRecyclerView.getChildAdapterPosition(targetView) == 0)            || (helper.getDecoratedEnd(targetView) == helper.getEndAfterPadding()            && mRecyclerView.getChildAdapterPosition(targetView) == mRecyclerView.getAdapter().getItemCount() - 1))        return 0;    int viewCenter = helper.getDecoratedStart(targetView) + (helper.getDecoratedEnd(targetView) - helper.getDecoratedStart(targetView)) / 2;    int correctCenter = (helper.getEndAfterPadding() - helper.getStartAfterPadding()) / 2;    return viewCenter - correctCenter;}private OrientationHelper getVerticalHelper(RecyclerView.LayoutManager layoutManager) {    if (mVerticalHelper == null) {        mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);    }    return mVerticalHelper;}private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) {    if (mHorizontalHelper == null) {        mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);    }    return mHorizontalHelper;}

}


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Android RecyclerView单击、长按事件标准实现:基于OnItemTouchListener + GestureDetector
Android RecyclerView实现下拉列表功能
RecyclerView使用介绍
关于recyclerview加载更多,瀑布流等
SuitedRecyclerView 一个根据自身大小自适应的 RecyclerView,自定义了 LayoutManag @codeKK Android 开源站
Android 属性动画实战
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服