Is there any way to removing divider after a footer in a Recyclerview.I am using item decoration to add divider to the adapter.I am adding footer in the adapter.divider is showing below the footer also.i want to remove it.
This is my code for Divider
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 rect, View view, RecyclerView parent, RecyclerView.State state) {
if (Orientation == VERTICAL_LIST) {
rect.set(0, 0, 0, Divider.getIntrinsicHeight());
} else {
rect.set(0, 0, Divider.getIntrinsicWidth(), 0);
}}
You have to add a check on getItemOffsets() method:
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
// set the rect's size
}
}
You can find an example of this implementation on my RecyclerViewDivider library on Github
Or you can simply add it as a Gradle dependency and check the javadoc:
dependencies {
...
compile 'com.github.fondesa:recycler-view-divider:1.1.3'
}
And use:
RecyclerViewDivider.with(context)
.addTo(recyclerView)
.visibilityFactory(new VisibilityFactory() {
#Override
public boolean displayDividerForItem(int listSize, int position) {
return position != listSize - 1;
}
})
.build()
.attach()
Related
I have RecyclerView item decoration and add my RecyclerView. RecyclerView divider lost when change item background color.
My RecyclerView with divider:
When RecyclerView items selected, not show divider:
setBackgroundColor:
private void setBackgroundColor() {
if (selectedItem.isEmpty() || !selectedItem.contains(item)) {
this.setBackgroundColor(Color.TRANSPARENT);
} else {
this.setBackgroundColor(0xffffedc7);
}
}
DividerItemDecoration:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
public DividerItemDecoration(int resId) {
mDivider = ContextCompat.getDrawable(MyApplication.getContext(), resId);
}
#Override
public void onDraw(#NonNull Canvas canvas, RecyclerView parent, #NonNull RecyclerView.State state) {
int left = MyApplication.getContext().getResources().getDimensionPixelSize(R.dimen.profileImageSizeDivider);
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(canvas);
}
}
}
Try this:
/**
* Draws left or right inset dividers at the bottom of every recycler item view. Only supports
* vertical orientations.
*/
public class InsetDividerItemDecoration extends RecyclerView.ItemDecoration {
private int mLeftInset = 0;
private int mRightInset = 0;
private int mStartPosition = 0;
final private Paint mLinePaint = new Paint();
final private List<Integer> mPositionsToIgnore = new ArrayList<>();
public InsetDividerItemDecoration(int leftInset, int rightInset, int dividerColor) {
mLeftInset = leftInset;
mRightInset = rightInset;
setColor(dividerColor);
}
public InsetDividerItemDecoration(int leftInset, int rightInset, int dividerColor, int startPosition) {
mLeftInset = leftInset;
mRightInset = rightInset;
mStartPosition = startPosition;
setColor(dividerColor);
}
public InsetDividerItemDecoration(int leftInset, int rightInset, int dividerColor, int startPosition, int dividerHeight) {
mLeftInset = leftInset;
mRightInset = rightInset;
mStartPosition = startPosition;
setColor(dividerColor);
setDividerHeight(dividerHeight);
}
public InsetDividerItemDecoration(int leftInset, int rightInset) {
this(leftInset, rightInset, 0);
}
public int getColor() {
return mLinePaint.getColor();
}
public void setColor(int color) {
mLinePaint.setColor(color);
}
public int getLeftInset() {
return mLeftInset;
}
public void setLeftInset(int leftInset) {
mLeftInset = leftInset;
}
public int getRightInset() {
return mRightInset;
}
public void setRightInset(int rightInset) {
mRightInset = rightInset;
}
public void setDividerHeight(int height) {
mLinePaint.setStrokeWidth(height);
}
public int getDividerHeight() {
return (int) mLinePaint.getStrokeWidth();
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
final int visibleItems = parent.getLayoutManager().getChildCount();
for (int i = 0; i < visibleItems; i++) {
View itemView = parent.getLayoutManager().getChildAt(i);
final int adapterPosition = parent.getChildAdapterPosition(itemView);
final boolean shouldDraw = adapterPosition != RecyclerView.NO_POSITION
&& adapterPosition != parent.getAdapter().getItemCount() - 1
&& adapterPosition >= mStartPosition
&& !shouldIgnoreAdapterPosition(adapterPosition);
if (shouldDraw) {
Rect itemRect = new Rect();
itemView.getDrawingRect(itemRect);
parent.offsetDescendantRectToMyCoords(itemView, itemRect);
final int lineStartX = mLeftInset;
final int lineStartY = itemRect.bottom;
final int lineEndX = itemRect.right - mRightInset;
final int lineEndY = lineStartY;
c.drawLine(lineStartX, lineStartY, lineEndX, lineEndY, mLinePaint);
}
}
}
protected boolean shouldIgnoreAdapterPosition(int position) {
return mPositionsToIgnore.size() > 0 && mPositionsToIgnore.contains(position);
}
public void setStartPosition(int startPosition) {
mStartPosition = startPosition;
}
public void setPositionsToIgnore(List<Integer> positionsToIgnore) {
mPositionsToIgnore.clear();
if (positionsToIgnore != null) {
mPositionsToIgnore.addAll(positionsToIgnore);
}
}
public void setPositionsToIgnore(Integer[] positionsToIgnore) {
setPositionsToIgnore(Arrays.asList(positionsToIgnore));
}
}
Currently my divider is only drawing one width:
How would can I add an extra divider for every increment position in my recyclerview?
Here is my ItemDecoration class:
public SimpleDivider(Context mContext, ArrayList<Integer> mDepth) {
mDivider = ContextCompat.getDrawable(mContext, R.drawable.recycler_view_divider);
this.mContext = mContext;
this.mDepth = mDepth;
dividerMargin = 15;
}
#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) {
int right = dividerMargin;
int left = 0;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
Edit1: Here's the Adapter. I thought it wouldn't be needed because all the logic would be written inside the ItemDecoration class.
private ArrayList<String> mList;
public class ViewHolder extends RecyclerView.ViewHolder{
TextView singleMessageComment;
public ViewHolder(#NonNull View itemView) {
super(itemView);
singleMessageComment = itemView.findViewById(R.id.item_child_comment);
}
}
public AdapterTest(ArrayList<String> mList) {
this.mList = mList;
}
#NonNull
#Override
public AdapterTest.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_single_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull AdapterTest.ViewHolder viewHolder, int i) {
viewHolder.singleMessageComment.setText(mList.get(i));
}
#Override
public int getItemCount() {
return mList.size();
}
Adding decorations:
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayout.VERTICAL));
recyclerView.addItemDecoration(new LeftDividerItemDecorator(this));
Declaration of the left divider item decorator:
public class LeftDividerItemDecorator extends RecyclerView.ItemDecoration {
private final Drawable mDivider;
private final Rect mBounds = new Rect();
private final Context mContext;
LeftDividerItemDecorator(Context context) {
mContext = context;
mDivider = context.getResources().getDrawable(R.drawable.divider);
}
public void onDraw(#NonNull Canvas c, #NonNull RecyclerView parent, #NonNull RecyclerView.State state) {
if (parent.getLayoutManager() != null && mDivider != null) {
drawLeftDivider(c, parent);
}
}
private void drawLeftDivider(Canvas canvas, RecyclerView parent) {
canvas.save();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; ++i) {
View child = parent.getChildAt(i);
parent.getDecoratedBoundsWithMargins(child, mBounds);
int childAdapterPosition = parent.getChildAdapterPosition(child);
int left = parent.getPaddingLeft();
// Solid size according to divider.xml width
//int right = left + (mDivider.getIntrinsicWidth());
// Dynamic size according to divider.xml width multiplied by child number
int right = left + (mDivider.getIntrinsicWidth() * (childAdapterPosition + 1));
int top = child.getTop();
int bottom = child.getBottom();
// Draw left vertical divider
mDivider.setBounds(
left,
top,
right,
bottom
);
mDivider.draw(canvas);
}
canvas.restore();
}
// Handles dividers width - move current views to right
public void getItemOffsets(#NonNull Rect outRect, #NonNull View view, #NonNull RecyclerView parent, #NonNull RecyclerView.State state) {
if (mDivider == null) {
outRect.set(0, 0, 0, 0);
} else {
int childAdapterPosition = parent.getChildAdapterPosition(view);
outRect.set(mDivider.getIntrinsicWidth() * childAdapterPosition, 0, 0, 0);
}
}
}
Divider's xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="4dp"
android:height="4dp" />
<solid android:color="#color/colorAccent" />
</shape>
Preview:
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.
A RecyclerView is nested in a CardView. I tried to call addItemDecoration() to add dividers into RecycylerView,but it didn't work.
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="#color/white_color"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
card_view:cardElevation="3dp">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_saleproduct_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_saleproduct_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:visibility="visible" />
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.v7.widget.CardView>
The java code:
mSwipe = (SwipeRefreshLayout)view.findViewById(R.id.swipe_saleproduct_list);
mRecyclerView= (RecyclerView) view.findViewById(R.id.recycler_saleproduct_list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(UIUtils.getContext()));
mRecyclerView.addItemDecoration(new DividerItemDecoration(UIUtils.getContext(), DividerItemDecoration.VERTICAL_LIST));
SaleProductListAdapter saleProductListAdapter = new SaleProductListAdapter(UIUtils.getContext(), mRecyclerView, list, mSwipe);
mRecyclerView.setAdapter(saleProductListAdapter);
This below is a good example, take a look at it:
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);
}
}
}
And here is my Fragment, it works well, which divider is clear and thin:
public static class RecyclerViewFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_recyclerview, container, false);
RecyclerView recyclerView = (RecyclerView) root.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
RecyclerViewAdapter adapter = new RecyclerViewAdapter(getActivity(), getResources()
.getStringArray(R.array.countries));
recyclerView.setAdapter(adapter);
return root;
}
}
I hope you will be inspired.
The mDivider with System maybe NullPointerException on platform KitKat and below,so I suggest use mDivider with oneself like:
public MyDecoration(Context context, int orientation) {
mDivider = context.getResources().getDrawable(R.drawable.line_divider);
setOrientation(orientation);
}
And Here is the line_divider:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="1dp"
android:height="1dp" />
<solid android:color="#color/color_in_common_green" />
</shape>
It maybe work well
I use a RecyclerView with some dividers between items. I use a DividerDecorator to draw them. But on older android versions (API 8) it draws the complete background in my divider color. Here is my code:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private final Drawable mDivider;
private final int mHeight;
private int mOrientation;
public DividerItemDecoration( final Context context, final int orientation) {
mDivider = new ColorDrawable( context.getResources().getColor( R.color.divider) );
mHeight = dpToPx( 1f, context.getResources() );
setOrientation(orientation);
}
private int dpToPx( final float dp, final Resources resource ) {
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resource.getDisplayMetrics() );
return Math.max( 1, (int) px );
}
public void setOrientation( final int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDraw( final Canvas c, final RecyclerView parent, final RecyclerView.State state) {
if( mOrientation == VERTICAL_LIST ) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical( final Canvas c, final RecyclerView parent ) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
View child;
RecyclerView.LayoutParams params;
int top;
int bottom;
for( int position = 0; position < childCount; position++) {
child = parent.getChildAt(position);
params = (RecyclerView.LayoutParams) child.getLayoutParams();
top = child.getBottom() + params.bottomMargin;
bottom = top + mHeight;
mDivider.setBounds( left, top, right, bottom );
mDivider.draw(c);
}
}
public void drawHorizontal( final Canvas c, final RecyclerView parent ) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
View child;
RecyclerView.LayoutParams params;
int left;
int right;
for( int position = 0; position < childCount; position++) {
child = parent.getChildAt( position );
params = (RecyclerView.LayoutParams) child.getLayoutParams();
left = child.getRight() + params.rightMargin;
right = left + mHeight;
mDivider.setBounds( left, top, right, bottom );
mDivider.draw( c );
}
}
#Override
public void getItemOffsets( final Rect outRect, final View view, final RecyclerView parent, final RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set( 0 /*left*/, 0 /*top*/, 0 /*right*/, mHeight /*bottom*/ );
} else {
outRect.set( 0 /*left*/, 0 /*top*/, mHeight /*right*/, 0 /*bottom*/ );
}
}
}
Here is my log from divider coordinates and they look correct:
DividerItemDecoration﹕ divider=0, left=0, top=66, right=240, bottom=67
DividerItemDecoration﹕ divider=1, left=0, top=133, right=240, bottom=134
DividerItemDecoration﹕ divider=2, left=0, top=200, right=240, bottom=201
DividerItemDecoration﹕ divider=3, left=0, top=267, right=240, bottom=268