I'm making an app where I'm using RecyclerView
with SnapHelper
class to make a scrollable horizontal card stack. I have implemented that successfully however my problem is that the cards swipe to right direction and I want to swipe the cards on left direction.
I did some research on SO and found 1 and 2
But I still couldn't figure out how to set the scrolling position to left instead of right.
Please any help would be appreciated
Update: I'm still working on this hardly figured out much because it is still difficult to change the direction of scrolling in recyclerview so anyone still wants to help me are welcome.
I also found that FindSnapView
method passes the scroll position and direcion maybe i'm wrong but beow code might be the solution
**@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
if (layoutManager instanceof LadderLayoutManager) {
int pos = ((LadderLayoutManager) layoutManager).getFixedScrollPosition(
mDirection, mDirection != 0 ? 0.8f : 0.5f);
mDirection = 0;
if (pos != RecyclerView.NO_POSITION) {
return layoutManager.findViewByPosition(pos);
}
}
return null;
}**
My main class
public class MainActivity extends AppCompatActivity {
LadderLayoutManager llm;
RecyclerView rcv;
HSAdapter adapter;
int scrollToPosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
llm = new LadderLayoutManager(1.5f, 0.85f, LadderLayoutManager.HORIZONTAL).
setChildDecorateHelper(new LadderLayoutManager
.DefaultChildDecorateHelper(getResources().getDimension(R.dimen.item_max_elevation)));
llm.setChildPeekSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
30, getResources().getDisplayMetrics()));
llm.setMaxItemLayoutCount(5);
rcv = (RecyclerView) findViewById(R.id.rcv);
rcv.setLayoutManager(llm);
new LadderSimpleSnapHelper().attachToRecyclerView(rcv);
adapter = new HSAdapter();
rcv.setAdapter(adapter);
final SeekBar sb = (SeekBar) findViewById(R.id.sb);
}
My code for custom LayoutManager
public class LadderLayoutManager extends RecyclerView.LayoutManager implements RecyclerView.SmoothScroller.ScrollVectorProvider {
private static final int INVALIDATE_SCROLL_OFFSET = Integer.MAX_VALUE;
private static final float DEFAULT_CHILD_LAYOUT_OFFSET = 0.2f;
public static final int UNLIMITED = 0;
public static final int VERTICAL = 1;
public static final int HORIZONTAL = 0;
private boolean mCheckedChildSize;
private int[] mChildSize;
private int mChildPeekSize;
private int mChildPeekSizeInput;
private boolean mReverse;
private int mScrollOffset = INVALIDATE_SCROLL_OFFSET;
private float mItemHeightWidthRatio;
private float mScale;
private int mChildCount;
private float mVanishOffset = 0;
private Interpolator mInterpolator;
private int mOrientation;
private ChildDecorateHelper mDecorateHelper;
private int mMaxItemLayoutCount;
public LadderLayoutManager(float itemHeightWidthRatio) {
this(itemHeightWidthRatio, 0.9f, VERTICAL);
}
public LadderLayoutManager(float itemHeightWidthRatio, float scale, int orientation) {
this.mItemHeightWidthRatio = itemHeightWidthRatio;
this.mOrientation = orientation;
this.mScale = scale;
this.mChildSize = new int[2];
this.mInterpolator = new DecelerateInterpolator();
}
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(mChildSize[0], mChildSize[1]);
}
public LadderLayoutManager setChildDecorateHelper(ChildDecorateHelper layoutHelper) {
mDecorateHelper = layoutHelper;
return this;
}
public void setMaxItemLayoutCount(int count) {
mMaxItemLayoutCount = Math.max(2, count);
if (getChildCount() > 0) {
requestLayout();
}
}
public void setVanishOffset(float offset) {
mVanishOffset = offset;
if (getChildCount() > 0) {
requestLayout();
}
}
public void setChildPeekSize(int childPeekSize) {
mChildPeekSizeInput = childPeekSize;
mCheckedChildSize = false;
if (getChildCount() > 0) {
requestLayout();
}
}
public void setItemHeightWidthRatio(float itemHeightWidthRatio) {
mItemHeightWidthRatio = itemHeightWidthRatio;
mCheckedChildSize = false;
if (getChildCount() > 0) {
requestLayout();
}
}
public void setReverse(boolean reverse) {
if (mReverse != reverse) {
mReverse = reverse;
if (getChildCount() > 0) {
requestLayout();
}
}
}
public boolean isReverse() {
return mReverse;
}
public int getFixedScrollPosition(int direction, float fixValue) {
if (mCheckedChildSize) {
if (mScrollOffset % mChildSize[mOrientation] == 0) {
return RecyclerView.NO_POSITION;
}
float position = mScrollOffset * 1.0f / mChildSize[mOrientation];
return convert2AdapterPosition((int) (direction > 0 ? position + fixValue : position + (1 - fixValue)) - 1);
}
return RecyclerView.NO_POSITION;
}
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
super.onMeasure(recycler, state, widthSpec, heightSpec);
mCheckedChildSize = false;
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (state.getItemCount() == 0) {
removeAndRecycleAllViews(recycler);
return;
}
if (!mCheckedChildSize) {
if (mOrientation == VERTICAL) {
mChildSize[0] = getHorizontalSpace();
mChildSize[1] = (int) (mItemHeightWidthRatio * mChildSize[0]);
} else {
mChildSize[1] = getVerticalSpace();
mChildSize[0] = (int) (mChildSize[1] / mItemHeightWidthRatio);
}
mChildPeekSize = mChildPeekSizeInput == 0 ?
(int) (mChildSize[mOrientation] * DEFAULT_CHILD_LAYOUT_OFFSET) : mChildPeekSizeInput;
mCheckedChildSize = true;
}
int itemCount = getItemCount();
if (mReverse) {
mScrollOffset += (itemCount - mChildCount) * mChildSize[mOrientation];
}
mChildCount = itemCount;
mScrollOffset = makeScrollOffsetWithinRange(mScrollOffset);
fill(recycler);
}
public void fill(RecyclerView.Recycler recycler) {
int bottomItemPosition = (int) Math.floor(mScrollOffset / mChildSize[mOrientation]);//>=1
int bottomItemVisibleSize = mScrollOffset % mChildSize[mOrientation];
final float offsetPercent = mInterpolator.getInterpolation(
bottomItemVisibleSize * 1.0f / mChildSize[mOrientation]);//[0,1)
final int space = mOrientation == VERTICAL ? getVerticalSpace() : getHorizontalSpace();
ArrayList<ItemLayoutInfo> layoutInfos = new ArrayList<>();
for (int i = bottomItemPosition - 1, j = 1, remainSpace = space - mChildSize[mOrientation];
i >= 0; i--, j++) {
double maxOffset = mChildPeekSize * Math.pow(mScale, j);
int start = (int) (remainSpace - offsetPercent * maxOffset);
ItemLayoutInfo info = new ItemLayoutInfo(start,
(float) (Math.pow(mScale, j - 1) * (1 - offsetPercent * (1 - mScale))),
offsetPercent,
start * 1.0f / space
);
layoutInfos.add(0, info);
if (mMaxItemLayoutCount != UNLIMITED && j == mMaxItemLayoutCount - 1) {
if (offsetPercent != 0) {
info.start = remainSpace;
info.positionOffsetPercent = 0;
info.layoutPercent = remainSpace / space;
info.scaleXY = (float) Math.pow(mScale, j - 1);
}
break;
}
remainSpace -= maxOffset;
if (remainSpace <= 0) {
info.start = (int) (remainSpace + maxOffset);
info.positionOffsetPercent = 0;
info.layoutPercent = info.start / space;
info.scaleXY = (float) Math.pow(mScale, j - 1);
break;
}
}
if (bottomItemPosition < mChildCount) {
final int start = space - bottomItemVisibleSize;
layoutInfos.add(new ItemLayoutInfo(start, 1.0f,
bottomItemVisibleSize * 1.0f / mChildSize[mOrientation], start * 1.0f / space).
setIsBottom());
} else {
bottomItemPosition -= 1;
}
int layoutCount = layoutInfos.size();
final int startPos = bottomItemPosition - (layoutCount - 1);
final int endPos = bottomItemPosition;
final int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
View childView = getChildAt(i);
int pos = convert2LayoutPosition(getPosition(childView));
if (pos > endPos || pos < startPos) {
removeAndRecycleView(childView, recycler);
}
}
detachAndScrapAttachedViews(recycler);
for (int i = 0; i < layoutCount; i++) {
fillChild(recycler.getViewForPosition(convert2AdapterPosition(startPos + i)), layoutInfos.get(i));
}
}
private void fillChild(View view, ItemLayoutInfo layoutInfo) {
addView(view);
measureChildWithExactlySize(view);
final int scaleFix = (int) (mChildSize[mOrientation] * (1 - layoutInfo.scaleXY) / 2);
final float gap = (mOrientation == VERTICAL ? getHorizontalSpace() : getVerticalSpace())
- mChildSize[(mOrientation + 1) % 2] * layoutInfo.scaleXY;
if (mOrientation == VERTICAL) {
int left = (int) (getPaddingLeft() + (gap * 0.5 * mVanishOffset));
layoutDecoratedWithMargins(view, left, layoutInfo.start - scaleFix
, left + mChildSize[0], layoutInfo.start + mChildSize[1] - scaleFix);
} else {
int top = (int) (getPaddingTop() + (gap * 0.5 * mVanishOffset));
layoutDecoratedWithMargins(view, layoutInfo.start - scaleFix, top
, layoutInfo.start + mChildSize[0] - scaleFix, top + mChildSize[1]);
}
ViewCompat.setScaleX(view, layoutInfo.scaleXY);
ViewCompat.setScaleY(view, layoutInfo.scaleXY);
if (mDecorateHelper != null) {
mDecorateHelper.decorateChild(view, layoutInfo.positionOffsetPercent, layoutInfo.layoutPercent, layoutInfo.isBottom);
}
}
private void measureChildWithExactlySize(View child) {
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.g