RecyclerView.ItemDecorator left padding - android

I am using the https://gist.github.com/polbins/e37206fbc444207c0e92 ItemDecorator to draw a separator line under each item in a recycler view. However it draws a straight line from left to right.
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
How can I set a left non absolute padding to the separator like in the picture below? Is this even possible using ItemDecorator?
I could modify this
int left = parent.getPaddingLeft();
but it would be absolute. Any ideas?
How it looks like right now:
Item layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:clickable="true"
android:background="#drawable/recycler_item_background">
<TextView
android:id="#+id/mTextViewIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:padding="10dp"
android:text="#string/fa_search"
android:textSize="18sp"/>
<LinearLayout
android:id="#+id/wrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/mTextViewIcon"
android:layout_toEndOf="#id/mTextViewIcon"
android:orientation="vertical"
android:paddingLeft="25dp"
android:paddingStart="25dp">
<TextView
android:id="#+id/mTextViewTitle"
style="#style/Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/mTextViewSubtitle"
style="#style/SmallGray"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
View holder:
public static class ItemViewHolder extends BaseViewHolder {
#Bind(R.id.mTextViewIcon)
TextView mTextViewIcon;
#Bind(R.id.mTextViewTitle)
TextView mTextViewTitle;
#Bind(R.id.mTextViewSubtitle)
TextView mTextViewSubtitle;
public ParkzoneViewHolder(View mView) {
super(mView);
ButterKnife.bind(this, mView);
}
}
I am using TextView for the icon with a custom typeface, just for you're information.

Give this a try
public static class ItemViewHolder extends BaseViewHolder {
#Bind(R.id.mTextViewIcon)
TextView mTextViewIcon;
#Bind(R.id.mTextViewTitle)
TextView mTextViewTitle;
#Bind(R.id.mTextViewSubtitle)
TextView mTextViewSubtitle;
#Bind(R.id.wrapper)
LinearLayout mWrapperLayout;
public ParkzoneViewHolder(View mView) {
super(mView);
ButterKnife.bind(this, mView);
}
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
// You can get view holders from recyclerview in different ways,
// parent.getChildViewHolder(child)
// im thinking parent.getChildViewHolder(child)
// is reliable and so ill use that here.
// but you be sure to test it with the other methods too
// if the getChildViewHolder doesnt work
View child = parent.getChildAt(i);
ItemViewHolder holder = (ItemViewHolder) parent.getChildViewHolder(child);
int left = parent.getPaddingLeft() + child.getPaddingLeft()
+ holder.mTextViewIcon.getPaddingLeft() + holder.mTextViewIcon.getWidth()
+ holder.mWrapperLayout.getPaddingLeft();
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}

Related

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.

Add divider between NavigationViews

I need to add a divider between two NavigationViews in my app. (navigation_drawer_top and navigation_drawer_bottom).
I have tried this. But this added divider to top of the view. not at end of the first NavigationView(navigation_drawer_top).
<View android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/>
Here is my code
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/navigation_drawer_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start">
<android.support.design.widget.NavigationView
android:id="#+id/navigation_drawer_top"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="top"
android:background="#color/menuColor"
android:paddingLeft="50dp"
app:headerLayout="#layout/nav_header_main"
app:itemTextAppearance="#style/NavigationDrawerStyle"
app:itemTextColor="#color/menuTextColour"
app:menu="#menu/menu_navigation_drawer_top"
/>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_drawer_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/menuColor"
android:layout_gravity="bottom"
android:paddingLeft="50dp"
app:itemTextAppearance="#style/NavigationDrawerStyle"
app:itemTextColor="#color/menuTextColour"
app:menu="#menu/menu_navigation_drawer_bottom" />
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
try this
<View
android:layout_below="#+id/id_of_item_below_which_you_want_it"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/>
It's quite simple to do. All you need to do is make a group and put unique id to the groups. The unique id is what plays the real trick in adding a divider to your menu.
Here is a quick example for you,
<group android:id="#+id/group1" android:checkableBehavior="single" >
<item
android:id="#+id/item_1"
android:checked="true"
android:icon="#drawable/ic_1"
android:title="#string/title_1" />
</group>
<group android:id="#+id/group2" android:checkableBehavior="single" >
<item
android:id="#+id/item_2"
android:icon="#drawable/ic_2"
android:title="#string/title_2" />
</group>
This will surely add dividers to your menus.
EDIT
As you are adding menus programmatically, you should try to get access to each NavigationMenuView and add a decorator to them.
NavigationView navigationView = (NavigationView) findViewById(R.id.navigation);
NavigationMenuView navMenuView = (NavigationMenuView) navigationView.getChildAt(0);
navMenuView.addItemDecoration(new DividerItemDecoration(appContext,DividerItemDecoration.VERTICAL_LIST))
And here is the DividerItemDecoration class for you,
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
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 RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
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);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}

View not appearing at bottom of CardView?

Hi I have a simple CardView where I want to show a divider between each Cardview. The issue is, my View that I use as a divider never gets shown on the last CardView in my RecyclerView. Here is my attempt:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp"
card_view:cardElevation="0dp"
android:id="#+id/cv_news_feed">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
...Content...
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/material_color_grey_300" />
</android.support.v7.widget.CardView>
The divider shows up for every CardView except for the last for whatever reason and I'm not sure why this is occurring. Any help would be appreciated, thanks!
EDIT: Image posted:
Remove following view from your item
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/material_color_grey_300" />
and try to use ItemDecoration as follows
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
Utility.ItemDecorationConst);
recyclerView.addItemDecoration(5);
DividerItemDecoration.java
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public DividerItemDecoration(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.top = space;
outRect.bottom = space;
}
}
CardView is an extension of FrameLayout which means that your divider is not in the bottom of your CardView but in the top.
Place your divider in your LinearLayout instead.
Add layout_gravity attribute to the View:
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:background="#color/material_color_grey_300" />
You can try to this code , hope this can help you
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/tools"
android:id="#+id/cv_news_feed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp"
card_view:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
...Content...
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="#+id/cv_news_feed"
android:layout_marginTop="5dp"
android:background="#android:color/holo_red_dark" />
</RelativeLayout>
Create a class DividerItemDecoration:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by Lincoln on 30/10/15.
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
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 RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
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);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
Then set the item decoration using addItemDecoration() method before setting the adapter.
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
// set the adapter
recyclerView.setAdapter(mAdapter);
N.B. Remove the view that you are using in cardview layout to show the divider.
Try to put your divider into LinearLayout,i.e.:
You should use like this
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
...Content...
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/material_color_grey_300" />
</LinearLayout>
Because CardView extends FrameLayout so your devider will be behind LinearLayout content.

Android - How to add a dashed/dotted separator line for RecyclerView?

I have used the code from this answer to create a solid separator line for my RecyclerViews.
However, I would like the line to be dashed/dotted.
I already have a line_dashed.xml resource that I am using elsewhere in my app:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line" >
<stroke
android:color="#color/blue"
android:dashGap="12dp"
android:dashWidth="12dp"
android:width="1dp" />
</shape>
But if I try applying this as the drawable resource that is accessed via my call to recyclerView.addItemDecoration(new SimpleDividerItemDecoration(getContext())), no line is drawn at all.
How to solve so a dashed line is shown?
Just add your drawable resource into this item decorator.
DividerItemDecoration decorator = new DividerItemDecoration(ContextCompat.getDrawable(getContext(), R.drawable.line_dashed));
recyclerView.addItemDecoration(decorator);
and DividerItemDecorator class:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private int mPaddingLeft;
public DividerItemDecoration(Drawable divider) {
mDivider = divider;
mPaddingLeft = 0;
}
public DividerItemDecoration(Drawable divider, int paddingLeft) {
mDivider = divider;
mPaddingLeft = paddingLeft;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null) return;
if (parent.getChildAdapterPosition(view) < 1) return;
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.top = mDivider.getIntrinsicHeight();
} else {
outRect.left = mDivider.getIntrinsicWidth();
}
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mDivider == null) {
super.onDrawOver(c, parent, state);
return;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
final int left = parent.getPaddingLeft() + mPaddingLeft;
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 1; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int size = mDivider.getIntrinsicHeight();
final int top = child.getTop() - params.topMargin;
final int bottom = top + size;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
} else { //horizontal
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 1; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int size = mDivider.getIntrinsicWidth();
final int left = child.getLeft() - params.leftMargin;
final int right = left + size;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else
throw new IllegalStateException("DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
Should work I tested it.
UPDATE:
android:layerType="software"
add this parameter in xml for recyclerView
Also add size into your shape drawable:
<size android:height="1dp"/>
currently u can use DividerItemDecoration from the box.
recyclerView.apply {
layoutManager = LinearLayoutManager(this#YourFragment.context)
adapter = this#YourFragment.adapter
addItemDecoration(
DividerItemDecoration(
this#YourFragment.context,
DividerItemDecoration.VERTICAL
).apply {
context.getDrawable(R.drawable.divider)?.let {
setDrawable(it)
}
}
)
}
Use the next shape XML:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<size android:height="1dp" />
<solid android:color="#color/primary" />
<stroke
android:width="0.5dp"
android:color="#color/primary"
android:dashWidth="5dp"
android:dashGap="5dp" />
</shape>
Attention: The stroke width must be less than the height of the line. In another case, the line will be not drawn.
Draw dashed line in Android is not so easy deal. Drowable like you showed and even just draw dotted line on canwas (canvas.drawLine(..., paintWithDashEffect)) not always works (not for all devices). You may use android:layerType="software" or draw path. IMHO, the better solution is to not draw dotted line at all (draw just line). But if you really need dotted line, you can use #fearless answer or somethink like this:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Paint mPaint;
private int mDividerSize;
public DividerItemDecoration(int dividerSize) {
mDividerSize = dividerSize;
mPaint = new Paint();
mPaint.setColor(ContextCompat.getColor(context, R.color.colorAccent));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(dividerSize);
mPaint.setPathEffect(new DashPathEffect(new float[]{dashGap,dashWidth},0));
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.bottom = mDividerSize;
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
Path path = new Path();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin + mDividerSize/2;
path.moveTo(left, top);
path.lineTo(right, top);
}
c.drawPath(path, mPaint);
}
}

RecyclerView ItemDecoration: Spacing AND Divider

Below is how I'm doing the spacing for RecyclerView items. It's designed to work with both grids and lists. The spacing works.
What I can't figure out is how to insert a divider line as well. Any help doing so would be greatly appreciated.
SIDE NOTE: if you have a better way to implement the spacing than what I'm currently doing, I'd be very grateful as well :)
public class ItemOffsetDecoration extends RecyclerView.ItemDecoration {
private int numOfColumns;
private int listSize;
private int offsetInDp;
private boolean isGridView;
private boolean canScrollHorizontally;
private boolean isBottomRow = false;
public ItemOffsetDecoration(RecyclerView.LayoutManager manager, int listSize, int offsetInDp) {
this(manager, 1, listSize, offsetInDp);
}
public ItemOffsetDecoration(RecyclerView.LayoutManager manager, int numOfColumns, int listSize, int offsetInDp) {
this.numOfColumns = numOfColumns;
this.listSize = listSize;
this.offsetInDp = PixelConversionUtils.dpToPx(offsetInDp);
this.isGridView = manager instanceof GridLayoutManager;
this.canScrollHorizontally = manager.canScrollHorizontally();
}
#Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
// only do left/right spacing if grid or horizontal list
if (isGridView || canScrollHorizontally) {
outRect.left = offsetInDp;
outRect.right = offsetInDp;
}
// only do top/bottom spacing if grid or vertical list
if (isGridView || !canScrollHorizontally) {
int pos = parent.getChildAdapterPosition(view);
boolean isNotTopRow = pos >= numOfColumns;
// Don't add top spacing to top row
if (isNotTopRow) {
outRect.top = offsetInDp;
}
int columnIndex = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
if (pos >= (listSize - numOfColumns) && columnIndex == 0) {
isBottomRow = true;
}
// Don't add bottom spacing to bottom row
if (!isBottomRow && pos < (listSize - numOfColumns)) {
outRect.bottom = offsetInDp;
}
}
}
}
here's a quick visual of what I'm looking to do:
here's what I have:
here's what I want:
You can achieve desired look this way:
first, create a divider Drawable, for this example I've used a simple shape, but you could use default line divider or any other drawable:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size android:height="2dp" />
<size android:width="2dp" />
<solid android:color="#000000" />
</shape>
second, in your ItemOffsetDecoration declare Drawable and initialize it:
public class ItemOffsetDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
...
public ItemOffsetDecoration(...) {
mDivider = ContextCompat.getDrawable(context, R.drawable.item_divider);
}
}
third, override onDrawOver() method:
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (isGridView) {
drawVerticalDivider(c, parent);
} else {
drawVerticalDivider(c, parent);
drawHorizontalDivider(c, parent);
}
}
where drawVerticalDivider() & drawHorizontalDivider() are (might be a good idea to refactor them into the single method and control direction of the divider via parameter):
public void drawVerticalDivider(Canvas c, RecyclerView parent) {
if (parent.getChildCount() == 0) return;
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params =
(RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getLeft() - params.leftMargin - offsetInDp;
int right = child.getRight() + params.rightMargin + offsetInDp;
int top = child.getBottom() + params.bottomMargin + offsetInDp;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontalDivider(Canvas c, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params =
(RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getRight() + params.rightMargin + offsetInDp;
int right = left + mDivider.getIntrinsicWidth();
int top = child.getTop() - params.topMargin - offsetInDp;
int bottom = child.getBottom() + params.bottomMargin + offsetInDp;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
Result for the Linear and Grid LayoutManagers:
Try placing the following XML snippet to get a divider:
<View android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="72dp"
android:layout_marginRight="16dp"
android:background="123e4152"/>
You can put this in the recyclerView's item layout beneath your items. Also Play around with the margins and background to suit your list.
haha……actualy,i had try like this for Divider ,although with a bit funny : first make you recycleview backgroud with Deep color,and make item_view backgroud white,then marginbottom for every item -> I'm serious, do not vote down :)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_marginBottom="2dp"
android:layout_height="wrap_content">
<TextView
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<TextView
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>

Categories

Resources