Decoration spacing and span with GridLayoutManger in RecyclerVIew - android

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.");
}
}
}

Related

How to scroll only one item by one in recyclerview?

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

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:

recycler view gridmanager layout column spacing does not give equal space in all side

enter image description here//I have recycler view as follows in xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/grid_recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:background="#f8f9fb"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/list_recycle_view"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
</LinearLayout>
//in my onprepareGridView method i have done following
private void prepareGridRecycleView() {
gridRecyclerView.setHasFixedSize(true);
SpaceItemDecoration itemDecoration = new SpaceItemDecoration(10);
gridRecyclerView.setClipToPadding(false);
gridRecyclerView.addItemDecoration(itemDecoration);
adapter = new ShopPageGridViewAdapter(ShopPageContent.this, new ShopPageHeaderGridInterface() {
#Override
public void onClick(boolean isClicked) {
gridRecyclerView.setVisibility(View.INVISIBLE);
listRecycleView.setVisibility(View.VISIBLE);
}
}, new ShopPageHeaderListInterface() {
#Override
public void onClick(boolean isClicked) {
}
}, new CartCoordivateInfoHolder() {
#Override
public void setViewCoordinate(ImageView view, int x, int y) {
view.setVisibility(View.VISIBLE);
view.bringToFront();
view.invalidate();
int pos[] = new int[2];
cart.getLocationOnScreen(pos);
Log.e("x", String.valueOf(pos[0]));
Log.e("y", String.valueOf(pos[1]));
TranslateAnimation anim = new TranslateAnimation(0, pos[0] - x, 0, pos[1] - y);
anim.setDuration(5000);
anim.setFillAfter(true);
view.startAnimation(anim);
}
});
final GridLayoutManager manager = new GridLayoutManager(this, 2);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return adapter.isPositionHeader(position) ? manager.getSpanCount() : 1;
}
});
gridRecyclerView.setAdapter(adapter);
gridRecyclerView.setLayoutManager(manager);
}
//and the item decorator class looks like the following
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpaceItemDecoration(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
if (position == 0) {
outRect.left = 0;
outRect.right = 0;
outRect.bottom = 0;
outRect.top = 0;
return;
}
if (parent.getChildAdapterPosition(view) == 1 || parent.getChildAdapterPosition(view) == 2) {
outRect.top = 0;
outRect.left =(space);
outRect.right = space;
outRect.bottom = space;
return;
}
outRect.left = space;[enter image description here][1]
outRect.right = space;
outRect.bottom = space;
outRect.top = space;
}
}
//The problem i am facing is space at the left side and right side different. Left side space are smaller than the right side space.
//image link
Try to:
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpaceItemDecoration(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
outRect.top = space;
if(position%2==0){
outRect.left = 0;
}
}
}
This code is not tested;

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
}
}
});

RecyclerView item decoration

I have a RecyclerView with a GridLayoutManager.
I set a custom ItemDecoration:
public class ListDetailsItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public ListDetailsItemDecoration(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int itemPosition = parent.getChildPosition(view);
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
if(itemPosition == 0 || itemPosition == 1) {
outRect.top = space;
}
if(itemPosition % 2 == 0) {
outRect.right = space / 2;
} else {
outRect.left = space / 2;
}
}
}
It works great until I need to remove anyone.
notifyItemRemoved(position);
The grid isn't resized.
Any ideas?

Categories

Resources