How to scroll only one item by one in recyclerview? - android

I have a horizontal list which it's using a recycler view and a PagerSnapHelper to simulate a view pager.
I want to swipe scroll one element at the time, but the problem is that i can scroll to the last element with one swipe.
So my problem is that I want to stop the swipe after one element swiped so if someone has any advice will be appreciated.

You could try adding a logic by checking the current position as mentioned in below post:
SnapHelper Item Position
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
View centerView = snapHelper.findSnapView(mLayoutManager);
int pos = mLayoutManager.getPosition(centerView);
Log.e("Snapped Item Position:",""+pos);
}
}
or Something like this:
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);
Ref: https://ogeek.cn/qa/?qa=441913/&show=441914

Related

Decoration spacing and span with GridLayoutManger in RecyclerVIew

I am trying to implement this kind of RecyclerView by using GridLayoutMangaer as its layout. However, I am facing the issue while implementing the item spacing for each item in the grid.
My aim is to have an implementation like image below
Please click on this link to preview image
Any solutions for this kind of implementation would be appreciated
public class GridRec extends RecyclerView.ItemDecoration {
private int space;
public GridRec(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
} else {
outRect.top = 0;
}
}
}
int my_space = getResources().getDimension(R.dimen.test);
myRecyclerView.addItemDecoration(new GridRec(my_space));
-----------------------------------------------------------
public class abc extends RecyclerView.ItemDecoration {
private int myPadding_psx;
private int myPadding_edge_psx;
public abc(Activity activity) {
final Resources resources = activity.getResources();
myPadding_psx = (int) resources.getDimension(R.dimen.myDefault);
myPadding_edge_psx = (int) resources.getDimension(R.dimen.mYDefaultEdge);
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
final int itemPosition = parent.getChildAdapterPosition(view);
if (itemPosition == RecyclerView.NO_POSITION) {
return;
}
int orientation = getOrientation(parent);
final int itemCount = state.getItemCount();
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
//Horizontal
if (orientation == LinearLayoutManager.HORIZONTAL) {
left = myPadding_psx;
right =myPadding_psx;
if (itemPosition == 0) {
left += myPadding_edge_psx;
}
else if (itemCount > 0 && itemPosition == itemCount - 1) {
right += myPadding_edge_psx;
}
}
//Vertical
else {
top = myPadding_psx;
bottom = myPadding_psx;
if (itemPosition == 0) {
top += myPadding_edge_psx;
}
else if (itemCount > 0 && itemPosition == itemCount - 1) {
bottom += myPadding_edge_psx;
}
}
if (!isReverseLayout(parent)) {
outRect.set(left, top, right, bottom);
} else {
outRect.set(right, bottom, left, top);
}
}
private boolean isReverseLayout(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getReverseLayout();
} else {
throw new IllegalStateException("Error.");
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else {
throw new IllegalStateException("Error.");
}
}
}

Item decoration show below the last row if RecycleView's height is not over the screen

If I use RecycleView with a vertical GridLayoutManager or StaggeredGridLayoutManager, when the RecycleView's Height is not over the screen, the decoration will be shown below the last row (which is not what I want)
I thougt it might be something wrong in the getItemOffset() method?
here is the decoration code:
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawHorizontal(c, parent);
drawVertical(c, parent);
}
private void drawHorizontal(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin + dividerSize;
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + dividerSize;
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
private void drawVertical(Canvas c, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + dividerSize;
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect,
View view,
RecyclerView parent,
RecyclerView.State state) {
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
int itemPosition = parent.getChildAdapterPosition(view);
if (isLastRaw(parent, itemPosition, spanCount, childCount) &&
isLastColum(parent, itemPosition, spanCount, childCount)) {
outRect.set(0, 0, 0, 0);
} else if (isLastRaw(parent, itemPosition, spanCount, childCount)) {
outRect.set(0, 0, dividerSize, 0);
} else if (isLastColum(parent, itemPosition, spanCount, childCount)) {
outRect.set(0, 0, 0, dividerSize);
} else {
outRect.set(0, 0, dividerSize, dividerSize);
}
}
private int getSpanCount(RecyclerView parent) {
int spanCount = -1;
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
}
return spanCount;
}
private boolean isLastColum(RecyclerView parent, int position, int spanCount, int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
if ((position + 1) % spanCount == 0) {
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
if ((position + 1) % spanCount == 0) {
return true;
}
} else {
int columCount = childCount / spanCount;
if (childCount % columCount == 0) {
if (position + 1 > childCount - spanCount) {
return true;
}
} else {
if (position + 1 > childCount - childCount % columCount) {
return true;
}
}
}
}
return false;
}
private boolean isLastRaw(RecyclerView parent, int position, int spanCount, int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
int rawCount = childCount % spanCount == 0 ?
childCount / spanCount :
childCount / spanCount + 1;
int lastRawFirstPosition = rawCount * spanCount - spanCount + 1;
if (position + 1 >= lastRawFirstPosition) {
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
int rawCount = childCount % spanCount == 0 ?
childCount / spanCount :
childCount / spanCount + 1;
int lastRawFirstPosition = rawCount * spanCount - spanCount + 1;
if (position + 1 >= lastRawFirstPosition) {
return true;
}
} else {
if ((position + 1) % spanCount == 0) {
return true;
}
}
}
return false;
}
when the RecycleView's height is over the screen, the bottom of the RecycleView:
when the RecycleView's height is not over the screen, the bottom of the RecycleView:

RecyclerView horizontal multiple snap

I have a horizontal recyclerView that has 28 elements. I want to achieve the following: display only 7 items at once and if the user swipes to the right then scroll to the next 7 items and same if swipes to the left then scroll to the previous 7 items. I have tried to solve it with the LinearSnapHelper like this:
public class CustomSnapHelper extends 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 - 7;
} else {
targetPosition = position + 7;
}
}
final int firstItem = 0;
final int lastItem = layoutManager.getItemCount() - 1;
targetPosition = Math.min(lastItem, Math.max(targetPosition, firstItem));
return targetPosition;
}
}
But the problems are
If I drag the list and scroll a few positions and release it then it won't go back to the
original snapped position.
Sometimes (based on the velocity) If I
swipe to right when the first 7 item is displayed, then it scrolls
an additional space and snaps to the wrong position and the items
from 9-15 are displayed.

How to find if the RecyclerView is being Scrolled up or down

I have a RecyclerView with GridLayoutManager , i want to find inside the method getItemOffsets of the Class RecyclerView.ItemDecoration if the user is scrolling up or down . Below is my code inside the class GridDividerDecoration where i draw borders between the items.
public class GridDividerDecorations extends RecyclerView.ItemDecoration {
private int mInsets;
List<Integer> itemsHeaderPos= new ArrayList<>();
List<Integer> itemsPos= new ArrayList<>();
List<GadgetItem> mList = new ArrayList<>();
int lastItem;
int itemPosition, itemposition2 = 0;
public GridDividerDecorations(Context context,List<GadgetItem> mList ) {
this.mList = mList;
mInsets = 6;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
if ((parent.getAdapter().getItemViewType(itemPosition) == 0))
itemsHeaderPos.add(itemPosition);
if((parent.getAdapter().getItemViewType(itemPosition) != 0))
itemsPos.add(itemPosition);
outRect.top = mInsets;
GridLayoutManager layoutManager = (GridLayoutManager)parent.getLayoutManager();
if(itemPosition == layoutManager.findLastVisibleItemPosition())
outRect.right = mInsets;
if (itemPosition % 2 == 0 && itemsHeaderPos.get(itemsHeaderPos.size() - 1) % 2 == 0) {
if (parent.getAdapter().getItemViewType(itemPosition) != 0)
outRect.left = mInsets;
} else if (itemPosition % 2 == 0 && itemsHeaderPos.get(itemsHeaderPos.size() - 1) % 2 != 0) {
if (parent.getAdapter().getItemViewType(itemPosition) != 0) {
outRect.right = mInsets;
}
}
}
}
The thing is that when I scroll up the dividers are painted upside down, so finding if the user scroll ups i can revert my implementation. Thank you!
You can determine if scrolled up or down with an OnScrollChangeListener:
recycler.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if(oldScrollY - scrollY > 0) {
// do stuff
}
else {
// do stuff
}
}
});

getScrollY StaggerGridView return 0

I'm using Android-ParallaxHeaderViewPager and StaggeredGridView to create layout like pinterest. I getting problem when getScrollY, the result is sometimes return 0 when scroll at central position on the first row gird , Where first row grid with 2 column/items and different height each items.
imaging :
this the code :
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount, int pagePosition) {
if (mViewPager.getCurrentItem() == pagePosition && visibleItemCount > 0) {
int scrollY = getScrollY(view); // sometimes return 0, when scroll at central position on the first row .
}
}
public int getScrollY(AbsListView view) {
View c = view.getChildAt(0);
if (c == null) {
return 0;
}
int firstVisiblePosition = view.getFirstVisiblePosition();
int top = c.getTop();
int headerHeight = 0;
if (firstVisiblePosition >= 1) {
headerHeight = mHeaderHeight;
}
return -top + firstVisiblePosition * c.getHeight() + headerHeight;
}
so how to fix it ?

Categories

Resources