提问者:小点点

Android回收视图水平-Snappy滚动效果


我正在使用cardviewRecyclerView中,并使RecyclerView水平滚动,我已经使用布局管理器初始化了视图,如下所示:

LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(layoutManager);

目前视图中的项目正在无休止地/平滑地滚动。我希望当一个项目显示在屏幕上时,它会停止,几乎就像一个快速的效果。这可以实现吗?

提前感谢。


共2个答案

匿名用户

我使用了这个类:

SnappyRecyclerView

package icn.premierandroid.misc;

import android.content.Context;
import android.content.res.Resources;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;

public class SnappyRecyclerView extends RecyclerView {

// Use it with a horizontal LinearLayoutManager
// Based on http://stackoverflow.com/a/29171652/4034572

public SnappyRecyclerView(Context context) {
    super(context);
}

public SnappyRecyclerView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
}

public SnappyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
public boolean fling(int velocityX, int velocityY) {

    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();

    int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;

    // views on the screen
    int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
    View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition);
    int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
    View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition);

    // distance we need to scroll
    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 (Math.abs(velocityX) < 1000) {
        // The fling is slow -> stay at the current page if we are less than half through,
        // or go to the next page if more than half through

        if (leftEdge > screenWidth / 2) {
            // go to next page
            smoothScrollBy(-scrollDistanceRight, 0);
        } else if (rightEdge < screenWidth / 2) {
            // go to next page
            smoothScrollBy(scrollDistanceLeft, 0);
        } else {
            // stay at current page
            if (velocityX > 0) {
                smoothScrollBy(-scrollDistanceRight, 0);
            } else {
                smoothScrollBy(scrollDistanceLeft, 0);
            }
        }
        return true;

    } else {
        // The fling is fast -> go to next page

        if (velocityX > 0) {
            smoothScrollBy(scrollDistanceLeft, 0);
        } else {
            smoothScrollBy(-scrollDistanceRight, 0);
        }
        return true;

    }

}

@Override
public void onScrollStateChanged(int state) {
    super.onScrollStateChanged(state);

    // If you tap on the phone while the RecyclerView is scrolling it will stop in the middle.
    // This code fixes this. This code is not strictly necessary but it improves the behaviour.

    if (state == SCROLL_STATE_IDLE) {
        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();

        int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;

        // views on the screen
        int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
        View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition);
        int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
        View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition);

        // distance we need to scroll
        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 (leftEdge > screenWidth / 2) {
            smoothScrollBy(-scrollDistanceRight, 0);
        } else if (rightEdge < screenWidth / 2) {
            smoothScrollBy(scrollDistanceLeft, 0);
        }
    }
}

}

在XML(把你的包路由到类,例如我的是icn. Premerandroid.misc.SnappyRecyclerView

 <packagename.SnappyRecyclerView
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/recycler_view"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:scrollbars="none"
            android:layout_weight="0.34" />

如果您的类中已经初始化了RecyclerView,则不需要更改任何内容。

像这样:

recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
                // LinearLayoutManager is used here, this will layout the elements in a similar fashion
                // to the way ListView would layout elements. The RecyclerView.LayoutManager defines how
                // elements are laid out.
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(mLayoutManager);

正如您所要求的,这应该只满足屏幕元素的全宽度。

匿名用户

您正在寻找的是捕捉效果。

我没有亲自使用过这门课,但我相信这对你有用。

https://gist.github.com/lauw/fc84f7d04f8c54e56d56

这所做的是,扩展当前Android的回收器视图并为其添加捕捉功能。

将此类添加到您的项目中,并用您当前的回收器视图替换回收器视图。

您可以使用setSnapEnable()方法将项目捕捉到屏幕上。