我正在尝试制作类似于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,我无法弄清楚它为什么会发生。
答案 0 :(得分: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
答案 1 :(得分:1)
我在水平列表中$
的接口回调中调用了&
方法。在调用接口之前,我正在设置所选项目,然后通知视图已更改,以便更新当前状态。这导致layoutmanager返回坏索引的所有问题。
一旦我做了一个空项目并测试了我的逻辑,我就发现了这一点。令我惊讶的是工作正常,这使我能够追查真正的问题。
一旦我在所有视图逻辑之前移动了snaplogic,一切都按预期工作,而不会更改我发布的代码。
希望这可以帮助将来的某个人。
答案 2 :(得分: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);
}
}
答案 3 :(得分:0)
这是因为输入的“位置”不是布局位置,请首先找到如下所示的布局位置,然后再应用smoothscrolltoposition。
asyncStorage