Development issue/problem:
What is the best and easiest way to decorate RecyclerView to make it look and feel like this?
The main problem is that there are only separators between the elements, but not between the elements and the left/right side of the screen.
Do you have any ideas?
How can I solve this problem?
Solution 1:
I don’t know why you need this, but this user interface is pretty easy to implement with the RecyclerView decorator.
3
10dp
You can customize the columns photo_list_preview_columns and photo_list_spacing to your liking.
mRecylerView.addItemDecoration(new ItemDecorationAlbumColumns(
getResources().getDimensionPixelSize(R.dimen.photos_list_spacing),
getResources().getInteger(R.integer.photo_list_preview_columns))))) ;
and decorator (must be pumped).
import android.graphics.Rect;import android.graphics.Rect;import android.support.v7.widget.RecyclerView;import android.view ;
public classArchivesDivisionDivisionDivision {
private int mSizeGridSpacingPx;
private int mGridSize ;
private boolean mNeedLeftSpacing = false ;
public ItemDecorationAlbumColumns(int gridSpacingPx, int gridSize) {
mSizeGridSpacingPx = gridSpacingPx;
mGridSize = gridSize;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int frameWidth = (int) ((parent.getWidth() – (float) mSizeGridSpacingPx * (mGridSize – 1)) / mGridSize);
int padding = parent.getWidth() / mGridSize – frameWidth;
int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
if (itemPosition
Solution 2:
Here’s a simpler and more practical implementation:
the MediaSpaceDecoration public class extends RecyclerView.itemDecoration {
private end-in-space;
private end-list allowedViewTypes = Arrays.asList(
R.layout.item_image,
R.layout.item_blur) ;
public MediaSpaceDecoration(int spacing) {
this.spacing = spacing;
}
@General
public void getItemOffsets(Rect outRect,
View view,
RecyclerView parent,
RecyclerView.State) {
final int position = parent.getChildAdapterPosition(view);
if (!isMedia(parent, position)) {
return;
}
endTotalSpanCount = getTotalSpanCount(parent);
int spanSize = getItemSpanSize(parent, position);
if (totalSpanCount == spanSize) {
return;
}
outRect.top = isInTheFirstRow(position, totalSpanCount) ? 0: distance;
outRect.left = isFirstInRow(position, totalSpanCount) ? 0: Distance / 2;
outRect.right = isLastInRow(position, totalSpanCount) ? 0: distance / 2;
outRect.bottom = 0; // not necessary
}
private boolean isInTheFirstRow(int position, int spanCount) { position returned
I also check before setting the Rect parameter, because I have a different range for each display type and I only need to add an extra spacing for the allowed display types. You can easily remove this check, and the code will be even easier. That’s what it looks like:
Solution 3:
You might get an answer, but I’ll still post my solution that might help others. It can be used for vertical, horizontal frames or grid views, passing alignment.
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view ;
The public class DividendInstrumentDecoration extends the RestoreView.ItemDecoration {.
private static endint[] ATTRS = new int[]{
android.R.attr.listDivider
}
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
public static final int GRID = 2 ;
Private Separation;
private intrigue;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.getStyledAttributes(ATTRS) ;
mDivider = a.getDrawable(0) ;
a.recycle() ;
setOrientation(orientation) ;
}
public invalid setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST && orientation != GRID) {
throw new IllegalArgumentException(invalid orientation);
}
mOrientation = orientation;
}
@Orientation
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.Status) {
if(mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else if(mOrientation == HORIZONTAL_LIST){
drawHorizontal(c, parent);
} else {
drawVertical(c, parent);
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
if (parent.getChildCount() == 0) returns;
final int left = parent.getPaddingLeft() ;
final int right = parent.getWidth() – parent.getPaddingRight() ;
final See child = parent.getChildAt(0);
if (child.getHeight() == 0) returns;
final RecyclerView.LayoutParams params =
(RecyclerView.LayoutParams) child.getLayoutParams() ;
int top = child.getBottom() + params.bottomMargin + mDivider.getIntrinsicHeight() ;
int bottom = top + mDivider.getIntrinsicHeight() ;
end int parentBottom = parent.getHeight() – parent.getPaddingBottom();
while (bottom)
Solution 4:
Another simple solution that worked for me. I hope it’s useful.
Class GridItemDecorator(val context : Context, private valDp : Int, private val mGridSize : Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view : View, parent: RecyclerView, indicate: RecyclerView.State) {
val resources = context.resources
val spacingPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, spacingDp.toFloat(), resources.displayMetrics)
trap bit = si (intervalPx > mGridSize) Math.round(intervalPx / mGridSize) else 1
trap itemPosition = (view.layoutParams as RecyclerView.LayoutParams).viewAdapterPosition
outRect.top = if (itemPosition)
Solution no. 5:
@Bindadapter({bind:adapter})public static-binding gap(RecyclerView view, RecyclerView.Adapteradapter) {view.setLayoutManager(new GridLayoutManager(view).getContext(), 3));view.addItemDecoration(new SpacesItemDecorationGrid(view.getContext(), 4, 3));view.setItemAnimator(new DefaultItemAnimator());view.setAdapter(adapter);}.
The SpacespaceDecorationGrid public class extends RestoreView.ItemDecoration {.
private int mSizeGridSpacingPx ;
private int mGridSize ;
private boolean mNeedLeftSpacing = false ;
/**
* @param gridSpacingPx
* @param gridSize
*/
SpacesItemDecorationGrid(Context context, int gridSpacingPx, int gridSize) {
mSizeGridSpacingPx = (int) Util.convertDpToPixel(gridSpacingPx, context);
mGridSize = gridSize;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int frameWidth = (int) ((parent.getWidth() – (float) mSizeGridSpacingPx * (mGridSize – 1)) / mGridSize);
int padding = parent.getWidth() / mGridSize – frameWidth;
int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
int itemCount = parent.getAdapter().getItemCount() – mGridSize ;
/* if (itemPosition itemCount) {
outRect.bottom = mSizeGridSpacingPx ;
} else {
outRect.bottom = 0 ;
}
}
}
Solution no. 6:
This is my execution in Kotlin. I changed the code from the other answers to also indicate the separator of the full elements.
import android.graphics.Rect
import android.view.View
import androidx.recyclingerview.widget.GridLayoutManager
import androidx.recyclingerview.widget.RecyclerView
class GridDividerItemDecoration (private trap interval : Int) : RecyclerView.ItemDecoration() {
Override fun getItemOffsets(outRect : Rect,view : View, parent: RecyclerView, status: RecyclerView.State) {valuedposition = parent.getChildAdapterPosition(view)
trap totalSpanCount = getTotalSpanCount(parent)
trap spanSize = getItemSpanSize(parent, position)
outRect.top = si (isInTheFirstRow(position, totalSpanCount)) 0 other distance
outRect.left = si (isFirstInRow(position, totalSpanCount, spanSize)) 0 other distance / 2
outRect.right = si (isLastInRow(position, totalSpanCount, spanSize)) 0 other distance / 2
outRect.bottom = 0
}
Private entertainment is ranked number one (position: Int, totalSpanCount: Int) : Boolean = position
Results :
Solution no. 7:
If you have a head, use it.
To hide the header, set the skipHeaderDivider=false separator, otherwise set true.
GridDividerItemDecoration class : ItemDecoration() {
var skipHeaderDivider = true
the private dimmer chicanery: Can you draw? = Zero.
limited private trap = Rect()
Interval between changes = 0
fun setDrawable(drawable: drawable) {
divider = drawable
divider ?.intrinsicHeight ?.let {space = it }
}
override fun opDraw(canvas:Canvas, parent:RecyclerView, state:RecyclerView.State) {
canvas.save()
val childCount = parent.childCount
for (i in 0 to childCount) {
val child = parent.getChildAt(i)
parent.layoutManager ?.getDecoratedBoundsWithMargins(child, limits)
Val Law: Int = border.right + child.translationX.roundToInt()
trap links : Int = border.left – child.translationX.roundToInt()
val bottom : Int = border.bottom + child.translationY.roundToInt()
trap top : Int = edge.top – child.translationY.roundToInt()
separator ?.setBounds(left, top, right, bottom)
separator ?.draw(canvas)
}
canvas.restore()
}
Override fun getItemOffsets(outRect : Rect,view : Image, parent: RecyclerView, status: RecyclerView.State) {valid gridLayoutManager = parent.layoutManager if ? GridLayoutManager: returns
val position = gridLayoutManager.getPosition(view)
if (position = itemCount – spanCount
var nextHeader = false)
output [protected via email] {for (i in 1..spanCount) {val nextSpanSize = gridLayoutManager.spanSizeLookup.getSpanSize(position + i)if (nextSpanSize == spanCount) {nextHeader = true[protected via email]}}}}}
outRect.top = interval
outRect.left = 0
outRect.right = interval
outRect.bottom = if (nextHeader | onBottom) interval again 0
}
}
Solution no. 8:
Here is my custom class that allows for equal spacing between grid cells in Cotlin:
class GridItemOffsetDecoration(private val spanCount : Int, private var mItemOffset : Int) : ItemDecoration() {
Override fun getItemOffsets(outRect: Rect, view : View, parent: RecyclerView,
: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
as (position
}
And to add it as an object decorator in RecyclerView, add the following line:
/*spanCount is the number of meshes, for example (2 = 2*2 meshes, 3 = 3*3)*/
binding.rvActiveChallenges.addItemDecoration(GridItemOffsetDecoration(2, resources.getDimensionPixelSize(R.dimen._10dp)).
Solution no. 9:
Here’s my version. Based on Nikolai’s response, but improved to handle a grid of three or more images and uses dp units for intervals. (The version does not give the same size/spacing of more than 2 images).
Note: the logic behind calculating the distance in each frame is more complex than simply dividing the distance by two (half for each frame), which most answers don’t take into account….
/**
* Class to add the EXTERNAL LOCATION to the element grid. Only works for a grid of 3 or more columns.
*/
class PhotoSpaceDecoration extends RecyclerView.ItemDecoration {
private final int spacingWidthPx ;
/**
* Initialize with spacesWidthDp in dp
*
* @ spacingWidthDp; this is distributed among the elements and applied as a spacing on each side
* NB : It should be divided by 2 and by the number of columns
*/
public PhotoSpaceDecoration(Context context, int spacesWidthDp) {
// Convert DP to pixels
this.spacingWidthPx = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, spacingWidthDp,
context.getResources().getDisplayMetrics());
}
/**
* @param index a 0-indexed value of the current item
* @param numberOfColumns
* @return a 0-indexed point with the x & y position of the item in the grid
*/
private Point getItemXY(int index, int numberOfColumns) {
int x = index % numberOfColumns;
int y = index / numberOfColumns; // NB : The integer division
gives the new period (x, y);
}
@General
public void getItemOffsets(Rect outRect, View View, RecyclerView parent, RecyclerView.State) {
last int position = parent.getChildAdapterPosition(view);
last int columns = getTotalSpanCount(parent);
last rows = (int) Math.ceil(parent.getChildCount() / (double) columns); // NB : NOT integer division
int spanSize = getItemSpanSize(parent, position);
if (columns == spanSize) {
return;
}
Item = getItemXY(position, columns);
int firstMargin = gapWidthPx * (columns – 1) / columns;
int secondMargin = gapWidthPx – firstMargin;
int middleMargin = gapWidthPx / 2 ;
if (dot.x == 0) { // first columnoutRect.left = 0;outRect.right = firstMargin;} else if (dot.x == 1) { // second columnoutRect.left = secondMargin;outRect.right = rows > 3 ? middleMargin: secondMargin;} else if (dot.x – columns == -2) { // penultimate columnoutRect.left = rows > 3 ? middleMargin: secondMargin;outRect.right = second Margin;} else if (dot.x – columns == -1) { // last columnoutRect.left = first Margin;outRect.right = 0;} else if (dot.x – columns == 0;} else if (dot.x – columns == -1) { // last columnoutRect.left = first Margin;outRect.right = 0;} other { // middle columnoutRect.left = middle Margin;outRect.right = middle Margin;}
if (dot.y == 0) { // first line
outRect.top = 0;
outRect.bottom = firstMargin;
} else if (dot.y == 1) { // second line
outRect.top = secondMargin;
outRect.bottom = lines > 3 ? middleMargin: secondMargin;
} else if (dot.y – lines == -2) { // penultimate line
outRect.top = lines > 3 ? middleMargin: secondMargin;
outRect.bottom = secondMargin;
} else if (dot.y – lines == -1) { // last line
outRect.top = firstMargin;
outRect.bottom = 0;
} other { // lines middle
outRect.top = middleMargin;
outRect.bottom = middleMargin;
}
}
private int getTotalSpanCount (RecyclerView parent) {
final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
return layoutManager instance of GridLayoutManager? ((GridLayoutManager) layoutManager).getSpanCount() : 1 ;
}
private int getItemSpanSize(RecyclerView parent, int position) {
final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
return layoutManager instance of GridLayoutManager? ((GridLayoutManager) layoutManager) .getSpanSizeLookup()
.getSpanSize(
position) : 1;
}
}
This applies to the Reworker view of Activity.onCreate(), as shown below.
photosRecyclerView.addItemDecoration(new PhotoSpaceDecoration(this, 6)) ;
Example:
Good luck!
Related Tags: