5

我正在尝试制作类似于 Instagram 过滤器布局的布局。基本上,当您选择一个过滤器时,它会滚动到您选择的项目 + 1,向您显示还有更多过滤器。

我目前正在尝试在这里LinearLayoutManager为我的水平建立一个自定义RecyclerView

public class LinearLayoutSnapManager extends LinearLayoutManager {
    private int mCurrentPos = 0;

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

    public LinearLayoutSnapManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public LinearLayoutSnapManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

    }


    public void snap(RecyclerView rv, int position) {
        if (mCurrentPos == position) {
            // No move
            return;
        }

        boolean goingRight = true;
        if (position < mCurrentPos) {
            goingRight = false;
        }
        mCurrentPos = position;
        smoothScrollToPosition(rv, new RecyclerView.State(), goingRight ? getScrollRightPos(): getScrollLeftPos());
    }

    private int getScrollLeftPos() {
        int newPos = mCurrentPos - 1;
        return (newPos > 0) ? newPos : 0;
    }

    private int getScrollRightPos() {
        return mCurrentPos + 1;
    }
}

向左滚动按预期工作,但是当我向右滚动时,它似乎只是跳到列表的末尾而不是 newItem + 1,我不知道为什么会发生这种情况。

在此处输入图像描述

4

4 回答 4

2

我在我的水平列表snap中的接口回调中调用我的方法。onclicklistener在调用界面之前,我正在设置所选项目,然后通知视图已更改以更新当前状态。这导致布局管理器返回错误索引的所有问题。

一旦我做了一个空项目并测试了我的逻辑,我就发现了这一点。令我惊讶的是,它工作得很好,这让我能够找到真正的问题。

一旦我在所有视图逻辑之前移动了 snaplogic,一切都按预期工作,而我发布的代码没有改变。

希望这可以帮助将来的人。

于 2016-11-05T15:50:42.270 回答
1

我会建议一个不同的解决方案。LinearLayoutManager附带方便的功能:

int findFirstCompletelyVisibleItemPosition()

返回第一个完全可见视图的适配器位置。


int findLastCompletelyVisibleItemPosition()

返回最后一个完全可见视图的适配器位置。


int findFirstVisibleItemPosition()

返回第一个可见视图的适配器位置。


int findFirstVisibleItemPosition()

返回最后一个可见视图的适配器位置。

前两个函数返回完全可见视图的位置,而后两个函数甚至返回部分可见视图。选择取决于您想要实现的行为。

使用它们时,功能getScrollLeftPos应该getScrollRightPos如下所示:

private int getScrollLeftPos() {
    int newPos = findFirstCompletelyVisibleItemPosition() - 1;
    return (newPos > 0) ? newPos : 0;
}

private int getScrollRightPos() {
    return findLastCompletelyVisibleItemPosition()+ 1;
}

并且不要调用方法:

smoothScrollToPosition(rv, new RecyclerView.State(), goingRight ? getScrollRightPos(): getScrollLeftPos());

LayoutManager. 如果您有对 的引用RecyclerView,请调用:

rv.smoothScrollToPosition(newPosition);

如果您查看源代码,RecyclerView您会发现这样的实现:

public void smoothScrollToPosition(int position) {
    if (mLayoutFrozen) {
        return;
    }
    if (mLayout == null) {
        Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +
                "Call setLayoutManager with a non-null argument.");
        return;
    }
    mLayout.smoothScrollToPosition(this, mState, position);
}

这与您的操作基本相同,但请注意,该函数LayoutManager是使用适当的 调用的RecyclerView.State。它只是符合RecyclerView

于 2016-11-03T15:34:55.447 回答
0

如果您希望第二次显示最后选择的过滤器(一个过滤器之前,几个过滤器之后),那么您没有正确的方法。

在这种情况下,无论方向是右还是左,过程都是相同的。RecyclerView 的位置总是比选定过滤器的位置小1,第一个元素除外。

(此示例未针对最新位置进行优化)

public class LinearLayoutSnapManager extends LinearLayoutManager {
    private int mCurrentSelectedPos = 0;

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

    public LinearLayoutSnapManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public LinearLayoutSnapManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

    }


    public void snap(RecyclerView rv, int selectedPosition) {
        if (mCurrentSelectedPos == selectedPosition) {
            // No move
            return;
        }

        mCurrentSelectedPos = selectedPosition;

        int newDisplayPos;
        if (mCurrentSelectedPos > 0) {
            newDisplayPos = mCurrentSelectedPos - 1;
        } else {
            newDisplayPos = 0;
        }

        smoothScrollToPosition(rv, new RecyclerView.State(), newDisplayPos);
    }

}
于 2016-11-03T09:04:45.857 回答
0

这是因为正在输入的“位置”不是布局位置,首先找到如下所示的布局位置,然后应用smoothscrolltoposition。

  Common.foodlistnuber = viewHolder.getLayoutPosition(); //position
  new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
  recyclerView.smoothScrollToPosition(Common.foodlistnuber);
        }
    }, 200);
于 2020-05-02T19:51:46.587 回答