RecyclerView水平滚动卡扣在中心

Ahm*_*wad 76 android horizontal-scrolling android-recyclerview

我正在尝试使用RecyclerView在这里制作类似旋转木马的视图,我希望项目在滚动时在屏幕中间捕捉,一次一个项目.我试过用了recyclerView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING);

但是视图仍然滚动顺畅,我也尝试使用滚动侦听器来实现我自己的逻辑,如下所示:

recyclerView.setOnScrollListener(new OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    Log.v("Offset ", recyclerView.getWidth() + "");
                    if (newState == 0) {
                        try {
                               recyclerView.smoothScrollToPosition(layoutManager.findLastVisibleItemPosition());
                                recyclerView.scrollBy(20,0);
                            if (layoutManager.findLastVisibleItemPosition() >= recyclerView.getAdapter().getItemCount() - 1) {
                                Beam refresh = new Beam();
                                refresh.execute(createUrl());
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
Run Code Online (Sandbox Code Playgroud)

从右到左的滑动现在工作正常,但不是相反,我在这里缺少什么?

raz*_*zle 132

有了LinearSnapHelper,现在很容易.

你需要做的就是:

SnapHelper helper = new LinearSnapHelper();
helper.attachToRecyclerView(recyclerView);
Run Code Online (Sandbox Code Playgroud)

更新

自25.1.0起可用,PagerSnapHelper可以帮助达到ViewPager类似的效果.像使用它一样使用它LinearSnapHelper.

旧的解决方法:

如果你希望它的行为类似于ViewPager,请尝试这样做:

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(recyclerView);
Run Code Online (Sandbox Code Playgroud)

上面的实现仅基于速度的方向返回当前项目旁边的位置(居中),而不管幅度如何.

前者是支持库版本24.2.0中包含的第一方解决方案.这意味着您必须将其添加到您的应用模块build.gradle或更新它.

compile "com.android.support:recyclerview-v7:24.2.0"
Run Code Online (Sandbox Code Playgroud)

  • 我将此标记为指出PagerSnapHelper的最佳解决方案 (2认同)

Alb*_*lvo 61

重要更新:

Google已在Android支持库24.2.0(2016年8月发布)中实现了此功能.该发行说明这样说:

添加了RecyclerView.OnFlingListener以支持自定义行为以响应flings.该SnapHelper类提供一个实现专门用于捕捉孩子的意见,并 LinearSnapHelper类扩展此实现以提供类似于居中对齐捕捉行为ViewPager.

请注意,我还没有尝试使用PagerSnapHelper.我仍然使用我的解决方案,工作正常.

原始答案:

经过几个小时的尝试,我在这里找到了3个不同的解决方案,我终于建立了一个解决方案,它模仿了a中的行为ViewPager.

该解决方案基于@eDizzle 解决方案,我相信我的改进足以说它的工作方式几乎就像一个ViewPager.

重要提示:我的RecyclerView项目宽度与屏幕完全相同.我没有尝试过其他尺寸.我也用水平方式LinearLayoutManager.我想如果你想垂直滚动,你需要调整代码.

在这里你有代码:

SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
Run Code Online (Sandbox Code Playgroud)

请享用!


Boo*_*tak 38

如果目标是使RecyclerView模仿行为ViewPager有相当简单的方法

RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);

LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
SnapHelper snapHelper = new PagerSnapHelper();
recyclerView.setLayoutManager(layoutManager);
snapHelper.attachToRecyclerView(mRecyclerView);
Run Code Online (Sandbox Code Playgroud)

通过使用PagerSnapHelper你可以得到像这样的行为ViewPager

  • 我使用`LinearSnapHelper`而不是`PagerSnapHelper`它适用于我 (4认同)

eDi*_*zle 30

你需要使用findFirstVisibleItemPosition来向相反的方向前进.并且为了检测滑动的方向,您需要获得投掷速度或x的变化.我从一个略微不同的角度来解决这个问题.

创建一个扩展RecyclerView类的新类,然后覆盖RecyclerView的fling方法,如下所示:

@Override
public boolean fling(int velocityX, int velocityY) {
    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();

//these four variables identify the views you see on screen.
    int lastVisibleView = linearLayoutManager.findLastVisibleItemPosition();
    int firstVisibleView = linearLayoutManager.findFirstVisibleItemPosition();
    View firstView = linearLayoutManager.findViewByPosition(firstVisibleView);
    View lastView = linearLayoutManager.findViewByPosition(lastVisibleView);

//these variables get the distance you need to scroll in order to center your views.
//my views have variable sizes, so I need to calculate side margins separately.     
//note the subtle difference in how right and left margins are calculated, as well as
//the resulting scroll distances.
    int leftMargin = (screenWidth - lastView.getWidth()) / 2;
    int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth();
    int leftEdge = lastView.getLeft();
    int rightEdge = firstView.getRight();
    int scrollDistanceLeft = leftEdge - leftMargin;
    int scrollDistanceRight = rightMargin - rightEdge;

//if(user swipes to the left) 
    if(velocityX > 0) smoothScrollBy(scrollDistanceLeft, 0);
    else smoothScrollBy(-scrollDistanceRight, 0);

    return true;
}
Run Code Online (Sandbox Code Playgroud)

  • @ltsai您可以更改为getWidth()(recyclerview.getWidth())而不是screenWidth.当RecyclerView小于屏幕宽度时,screenWidth无法正常工作. (3认同)

Far*_*zad 7

只需将padding和添加marginrecyclerViewrecyclerView item

回收者查看项目:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parentLayout"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_marginLeft="8dp" <!-- here -->
    android:layout_marginRight="8dp" <!-- here  -->
    android:layout_width="match_parent"
    android:layout_height="200dp">

   <!-- child views -->

</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

回收者视图:

<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="8dp" <!-- here -->
    android:paddingRight="8dp" <!-- here -->
    android:clipToPadding="false" <!-- important!-->
    android:scrollbars="none" />
Run Code Online (Sandbox Code Playgroud)

并设置PagerSnapHelper

int displayWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
parentLayout.getLayoutParams().width = displayWidth - Utils.dpToPx(16) * 4;
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
Run Code Online (Sandbox Code Playgroud)

dp 到 px:

public static int dpToPx(int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
}
Run Code Online (Sandbox Code Playgroud)

结果:

在此处输入图片说明