I have a recycler view where I want to add a space between the cells.
Using the code below works however, In the middle The space is doubled.
How can I space them and avoid the double space at the middle?
public class ItemDecorationAlbumColumns extends RecyclerView.ItemDecoration {
private int space;
public ItemDecorationAlbumColumns(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;
// Add top margin only for the first item to avoid double space between items
if(parent.getChildAdapterPosition(view) == 0) {
outRect.top = space;
}
}
}
Calling:
recyclerView.addItemDecoration(new ItemDecorationAlbumColumns(50));
Solved using the code below:
public class ItemDecorationAlbumColumns extends RecyclerView.ItemDecoration {
private int space;
public ItemDecorationAlbumColumns(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if(parent.getChildAdapterPosition(view) % 2 == 0) {
outRect.right = space;
outRect.bottom = space;
outRect.left = space/2;
} else {
outRect.left = space;
outRect.right = space/2;
outRect.bottom = space;
}
if(parent.getChildAdapterPosition(view) == 0) {
outRect.top = space;
outRect.left = space;
}
}
}
Related
StaggeredLayoutManager sometimes makes cells position disordered during scroll when trying to adjust them. I've a HeaderView and NormalViews in my RecyclerView. Following is the setup code:
int spacing = (int) getResources().getDimension(R.dimen.post_item_spacing);
mBindings.rvPosts.addItemDecoration(new PostsEqualGapItemDecoration(AppConstants.POSTS_SPAN_COUNT, spacing));
mPostsLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
mBindings.rvPosts.setLayoutManager(mPostsLayoutManager);
mProfileAdapter.setRecyclerView(mBindings.rvPosts);
mBindings.rvPosts.setAdapter(mAdapter);
mBindings.rvPosts.setNestedScrollingEnabled(false);
ItemDecoration class:
public class PostsEqualGapItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
public PostsEqualGapItemDecoration(int spanCount, int spacing) {
this.spanCount = spanCount;
this.spacing = spacing;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
if (layoutParams.isFullSpan()) {
outRect.set(0, 0, 0, 0);
} else {
int spanIndex = layoutParams.getSpanIndex();
int layoutPosition = layoutParams.getViewLayoutPosition();
int itemCount = parent.getAdapter().getItemCount();
boolean leftEdge = spanIndex == 0;
boolean rightEdge = spanIndex == (spanCount - 1);
boolean topEdge = spanIndex < spanCount;
boolean bottomEdge = layoutPosition >= (itemCount - spanCount);
int halfSpacing = spacing / 2;
/**
* Updated values to keep cells width same and spacing from left and right
* most item to be double than gap between items themselves.
*/
outRect.set(
leftEdge ? spacing * 2 : rightEdge ? 0 : spacing,
topEdge ? spacing : halfSpacing,
rightEdge ? spacing * 2 : leftEdge ? 0 : spacing,
bottomEdge ? spacing : 0
);
}
}
}
Screenshot:
You have to write custom item decoration for that case to your child item views
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(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;
// Add top margin only for the first item to avoid double space between items
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
} else {
outRect.top = 0;
}
}
}
I use ItemDecoration to set the space between the grid RecyclerView items, and I want the space between each item to be equal.
ItemDecoration
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) {
if (parent.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();
GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();
int spanSize = layoutParams.getSpanSize();
int spanIndex = layoutParams.getSpanIndex();
int totalSpanSize = gridLayoutManager.getSpanCount();
if (spanIndex == 0) {//left
outRect.left = space;
outRect.right = space / 2;
} else if (spanSize + spanIndex == totalSpanSize) {//right
outRect.right = space;
outRect.left = space / 2;
} else if (spanIndex > 0 && spanSize + spanIndex < totalSpanSize) {
outRect.left = space / 2;
outRect.right = space / 2;
}
outRect.bottom = space;
}
}
RecyclerView
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
item xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="90dp"
android:layout_height="90dp"
android:background="#ff6600"
android:orientation="vertical">
</LinearLayout>
Try this,
int spanCount;
final private Context mContext =YourActivity.this;
int value = activity.getResources().getConfiguration().orientation;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
recycler_view=(RecyclerView)findViewById(R.id.recycler_view);
recycler_view.setLayoutManager(new GridLayoutManager(mContext, 2));
if (value == Configuration.ORIENTATION_PORTRAIT) {
spanCount = 2;
}
else if (value == Configuration.ORIENTATION_LANDSCAPE) {
spanCount = 3;
}
int spacing_left = 50; // 50px
int spacing_top=10;
recycler_view.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing_left, spacing_top));
}
#Override
protected void onResume() {
if (value == Configuration.ORIENTATION_PORTRAIT) {
spanCount = 2;
}
else if (value == Configuration.ORIENTATION_LANDSCAPE) {
spanCount = 3;
}
super.onResume();
}
GridSpacingItemDecoration:
/* set spacing for grid view */
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration
{
final private int spanCount,spacing,spacing_top;
final private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing_left, int spacing_top)
{
this.spanCount = spanCount;
this.spacing = spacing_left;
this.includeEdge = true;
this.spacing_top=spacing_top;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
int position = parent.getChildAdapterPosition(view); // item phases_position
int column = position % spanCount; // item column
if (includeEdge)
{
outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
if (position < spanCount)
{ // top edge
outRect.top = spacing_top;
}
outRect.bottom = spacing_top; // item bottom
}
else
{
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount)
{
outRect.top = spacing_top; // item top
}
}
}
}
Use GridItemDecoration:
import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.DimenRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class GridItemDecoration extends RecyclerView.ItemDecoration {
private int mItemOffset;
public GridItemDecoration(int itemOffset) {
mItemOffset = itemOffset;
}
public GridItemDecoration(#NonNull Context context, #DimenRes int itemOffsetId) {
this(context.getResources().getDimensionPixelSize(itemOffsetId));
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(mItemOffset, mItemOffset, mItemOffset, mItemOffset);
}
}
From your Activity:
RecyclerView mRecyclerView;
RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
................
........................
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerView.setHasFixedSize(true);
// Grid layout manager
mLayoutManager = new GridLayoutManager(mContext, 3); // spanCount = 3 for 3 columns
mRecyclerView.setLayoutManager(mLayoutManager);
// Grid item spacing
GridItemDecoration itemDecoration = new GridItemDecoration(mContext, R.dimen.grid_item_spacing); // R.dimen.grid_item_spacing is 2dp
mRecyclerView.addItemDecoration(itemDecoration);
............
......................
}
Why don't you try to remove the code for the custom spacing, and use the grid parameters android:horizontalSpacing and android:verticalSpacing?
Add android:scaleType="fitXY" inside your item xml which will scale the image using FILL so that all items occupy same area.
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;
Currently trying to do that by using this class:
public class EqualItemSpacingDecoration extends RecyclerView.ItemDecoration {
private int space;
public EqualItemSpacingDecoration(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = space;
if (parent.getChildLayoutPosition(view) < 2)
outRect.top = space;
if (parent.getChildLayoutPosition(view) % 2 == 0) {
outRect.left = space;
outRect.right = space / 2;
} else {
outRect.left = space / 2;
outRect.right = space;
}
}
}
And use it with this code:
recycler.addItemDecoration(new EqualItemSpacingDecoration(12));
But the spacing isn't equal. The third item in the screenshot below has an incorrect spacing :
How will I be able to fix this issue?
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?