Two RecyclerView.ItemDecoration overlapping each other - android

In our app we use two ItemDecorations in RecyclerView. One is StickyHeader to show dates, and other is header to show New Messages header. Problem is that when they are added to same item, they overlap each other. How I can prevent this from happening.
StickyRecyclerHeadersDecoration headersDecoration = new StickyRecyclerHeadersDecoration(getAdapter());
recyclerView.addItemDecoration(headersDecoration);
NewMessageHeaderDecoration newMessageHeader = new NewMessageHeaderDecoration();
recyclerView.addItemDecoration(newMessageHeader);

I used this code from here to solve two ItemDecoration overlap. (For more details check comment by #bejibx)
public void drawVertical(Canvas c, RecyclerView parent)
{
RecyclerView.LayoutManager manager = parent.getLayoutManager();
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++)
{
final View child = parent.getChildAt(i);
final int top = manager.getDecoratedBottom(child);
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}

Related

RecyclerView - Shifting layout when creating item divider

I'm implementing a vertical divider for each of my viewHolders using itemDecoration. How would I make it so the layout draws the dividers first, and then it draws the views to the RIGHT of the dividers?
#Override
public void onDraw(#NonNull Canvas c, #NonNull RecyclerView parent, #NonNull RecyclerView.State state) {
int top = 0;
int bottom = parent.getHeight();
int childCount = parent.getChildCount();
for(int i = 0; i < childCount; ++i) {
View child = parent.getChildAt(i);
parent.getLayoutManager().getDecoratedBoundsWithMargins(child, this.mBounds);
int right = 150;
int left = 0;
this.mDivider.setBounds(left, top, right, bottom);
this.mDivider.draw(c);
}
}
You need to override getitemoffsets() as well. There you apply offsets to the items:
#Override
public void getItemOffsets(
Rect outRect,
View view,
RecyclerView parent,
RecyclerView.State state
) { outRect.left = 150; }

eliminate divider on top of the first item in the RecyclerView

I have a RecyclerView with an header on top( namely a title, a TextView that describe the content of the RecyclerView)
Now I combined two different ViewHolders with some logic into the Adapter to obtain this effect, but I have an unexpected result.
The recyclerView hava to have dividers, but I have a line I want to eliminate between the TextViewand the first Item of the `RecyclerView:
In other words I need to eliminate only the top divider of the RecyclerView,
the first item, because I want that between the TextView on top and the list below there is not separation, the other items instead I expect they are separated as I obtained
This post shows how to eliminate the last row divider of a RV, but i need the first top line and I have no idea how I can adapt this snippet to my use case, or if I should create a new class.
In the RecyclerView.ItemDecoration I want to identify the first view in the RecyclerView and not draw a decoration for it. I will also want to not reserve any space for the decoration since it is not drawn. This necessitates an override of getItemOffsets().
Here is some code that applies a decoration to the bottom of all RecyclerView items except the first and the last.
public class DividerItemDecorator extends RecyclerView.ItemDecoration {
private Drawable mDivider;
public DividerItemDecorator(Drawable divider) {
mDivider = divider;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int pos = parent.getChildAdapterPosition(view);
if (pos != 0 &&
pos != parent.getLayoutManager().getItemCount() - 1) {
outRect.bottom = mDivider.getIntrinsicHeight();
}
}
#Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
int dividerLeft = parent.getPaddingLeft();
int dividerRight = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
int pos = parent.getChildAdapterPosition(child);
if (pos != 0 &&
pos != parent.getLayoutManager().getItemCount() - 1) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int dividerTop = child.getBottom() + params.bottomMargin;
int dividerBottom = dividerTop + mDivider.getIntrinsicHeight();
mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
mDivider.draw(canvas);
}
}
}
}
Here is what this looks like. I have exaggerated the dividers so they would stand out.

android horizontal and vertical recyclerview item decoration

I currently have this Recyclerview with a solid line ItemDecoration separating the elements.:
but want to have a RecyclerView ItemDecoration with a style like this one:
This is my decoration with just solid vertical and horizontal lines without line spaces like my example :
public class GridDividerDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = {android.R.attr.listDivider};
private Drawable mDivider;
private int mInsets;
public GridDividerDecoration(Context context) {
TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
mInsets = context.getResources().getDimensionPixelSize(R.dimen.card_insets);
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawVertical(c, parent);
drawHorizontal(c, parent);
}
public void drawVertical(Canvas c, RecyclerView parent) {
if (parent.getChildCount() == 0) return;
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 left = child.getLeft() - params.leftMargin - mInsets;
final int right = child.getRight() + params.rightMargin + mInsets;
final int top = child.getBottom() + params.bottomMargin + mInsets;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(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 left = child.getRight() + params.rightMargin + mInsets;
final int right = left + mDivider.getIntrinsicWidth();
final int top = child.getTop() - params.topMargin - mInsets;
final int bottom = child.getBottom() + params.bottomMargin + mInsets;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.set(mInsets, mInsets, mInsets, mInsets);
}
}
anyone can help how to set some spaces between lines ?
You just want to have slightly shorter lines so just amend your bounds.
e.g:
For the vertical line, you have:
mDivider.setBounds(left, top, right, bottom);
so just change the top and bottom offsets like this:
mDivider.setBounds(left, top + 10, right, bottom - 10);
Do a similar thing for the horizontal lines but change the left and right offsets.
You can experiment with the actual values until you get the effect you want.

Draw multiple lines on a RecyclerView background

I'm trying to draw multiple horizontal lines on a RecyclerView background.
These lines have to be at a precise position, because there is a list of elements which have to fit between them. I could just add the lines to each element but I need those lines drawn, even if there are no elements added to the list.
How can I draw lines on the background? (I can't do it from the .xml) Thank you for your time!
Example image
It looks like you want to draw list dividers. I think you want to use ItemDecoration
When writing a decorator you want to make sure you account for translationY (handles item add/remove animation) and item offsets from other decorations (e.g. layoutManager.getDecoratedBottom(view))
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
private Drawable mDivider;
public DividerItemDecoration(Context context) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getLeft();
int right = parent.getRight();
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
int ty = (int) (child.getTranslationY() + 0.5f);
int top = layoutManager.getDecoratedBottom(child) + ty;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
recyclerView.addItemDecoration(new DividerItemDecoration(context));

How to Skip First Row in RecyclerView Item Decoration for GridLayout?

I'm using this ItemDecoration class for GridLayout -> https://github.com/devunwired/recyclerview-playground/blob/master/app/src/main/java/com/example/android/recyclerplayground/GridDividerDecoration.java
But the problem is, my first row in GridLayout is an image and I set the span to 2.
You can view my screen as per screenshot below :
How to skip the first row so that ItemDecoration didn't draw on the Image?
Below is the code that I'm using to add the ItemDecoration :-
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new GridLayoutManager(getActivity(), 2);
mLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return position == 0 ? 2 : 1;
}
});
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter.setHighlightsCallbacks(this);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addItemDecoration(new GridDividerDecoration(getActivity()));
I also modified the drawHorizontal method in GridDividerDecoration class to only draw if imageview is null but still not working :-
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
if (child.findViewById(R.id.home_imgHeader) == null) {
final RecyclerView.LayoutParams params =
(RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + params.rightMargin + mInsets;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
Any help?
Assuming your items don't individually have solid backgrounds (i.e. the white color is from the parent), the simplest fix would be to move the code from onDrawOver() to onDraw(). This will draw the gridlines underneath your child view contents and it will be hidden under the header image.
Otherwise, the code you are using assumes that the grid lines are always drawn to the top of the view in drawHorizontal() (notice top is a value that never changes). You would need to modify that function to account for the bottom of the first item and start drawing there. Something like:
public void drawHorizontal(Canvas c, RecyclerView parent) {
final View topView = parent.findViewHolderForAdapterPosition(0);
int viewBottom = -1;
if (topView != null) {
final RecyclerView.LayoutParams params =
(RecyclerView.LayoutParams) child.getLayoutParams();
viewBottom = child.getBottom() + params.bottomMargin + mInsets;
}
final int top = viewBottom > parent.getPaddingTop() ? viewBottom : parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
… /* Remaining Code */
}

Categories

Resources