yqritc / recyclerview-flexibledivider Goto Github PK
View Code? Open in Web Editor NEWAndroid library providing simple way to control divider items (ItemDecoration) of RecyclerView
License: Apache License 2.0
Android library providing simple way to control divider items (ItemDecoration) of RecyclerView
License: Apache License 2.0
How can I add the divider after a specific position.
I cannot seem to find it.
when set to true, divider is still showing
I can confirm that my adapter is implementing FlexibleDividerDecoration.VisibilityProvider and overriding shouldHideDivider. I can also confirm that shouldHideDivider is not being called
one divider with multiple color,and has the entry to set color place
VerticalItemDecoration Builder Has Protected access
Sorry.My English not good.
我认为应该分成 GridItemDecoration 和 LinearItemDecoration 。在每个item的周围绘制想要的divider。
这样实现起来比较简单。如果是GridLayoutManager,垂直的时候,则应该在最后一列右边 和 最后一行的下面不添加分割线。
下面是我写的一个例子,相信你能看懂
I think it should be divided into GridItemDecoration and LinearItemDecoration.Draw divider around each item instead of entire row / column.
If it's GridLayoutManager, you should not add the dividing line in the last column to the right and below the last line when vertical and vice versa.
I just like to think of it, it's easier for me to think of it, as the work that I do.
Here is an example of what I wrote, I believe you can understand
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
outRect.left = getDividerSize();
outRect.bottom = getDividerSize();
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
RecyclerView.Adapter adapter = parent.getAdapter();
int itemCount = adapter.getItemCount();
int position = parent.getChildAdapterPosition(view);
int spanCount = gridLayoutManager.getSpanCount();
GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
int spanIndex = spanSizeLookup.getSpanIndex(position, spanCount);
int spanGroupIndex = spanSizeLookup.getSpanGroupIndex(position, spanCount);
int lastSpanGroupIndex = spanSizeLookup.getSpanGroupIndex(itemCount - 1, spanCount);
if (lastSpanGroupIndex == spanGroupIndex) outRect.bottom = 0;
if (spanIndex == 0) outRect.left = 0;
return;
}
Log.e(TAG, "RecyclerView must have GridLayoutManager");
}
recyclerview-flexibledivider package was hosted on jcenter() but it is closed now.
Can you put it in another repository and can the change the read.me file
From the Material Design Spec
Dividers are placed along the bottom edge of the content tiles, independent of the grid.
The current implementation draws the dividers below the item:
if (mDividerType == DividerType.DRAWABLE) {
- bounds.top = child.getBottom() + params.topMargin + transitionY;
+ // I haven't tested the drawable implementation
+ bounds.top = child.getBottom() + params.topMargin + transitionY - dividerSize;
bounds.bottom = bounds.top + dividerSize;
} else {
- bounds.top = child.getBottom() + params.topMargin + dividerSize / 2 + transitionY;
+ // this one works great
+ bounds.top = child.getBottom() + params.topMargin - dividerSize / 2 + transitionY;
bounds.bottom = bounds.top;
}
and this can be removed because the size does not change
@Override
protected void setItemOffsets(Rect outRect, int position, RecyclerView parent) {
- outRect.set(0, 0, 0, getDividerSize(position, parent));
+ outRect.set(0, 0, 0, 0);
}
This feature should be optional
How to proguard this library?
I had to do the following in Lollipop, Nexus 5 in order to get a dashed line to show up.
recyclerView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Please add an option to add a divider above the first item. Thanks!
FlexibleDividerDecoration onDraw parent.getAdapter().getItemCount();
should check if adapter has set, if null just return.
Draw divider around items instead of entire row / column
Please add support for this, sometime we need to draw the divider for the last item.
Hi there,
Is there a way of changing the divider size depending not only on the position but also on the content?
In my case, my adapter extends from a CursorRecyclerAdapter and depending on the position content I set a different view type.
@Override
public int getItemViewType(int position) {
if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) {
String cursorUid = mCursor.getString(mCursor.getColumnIndex(ChatProvider.COL_FROM_UID));
String previousUid = "";
if (!mCursor.isFirst()) {
mCursor.moveToPrevious();
previousUid = mCursor.getString(mCursor.getColumnIndex(ChatProvider.COL_FROM_UID));
mCursor.moveToNext();
}
if (cursorUid.equals(uid))
return VIEW_TYPE_ME;
else if (previousUid.equals(cursorUid))
return VIEW_TYPE_OTHERS_BIS;
else
return VIEW_TYPE_OTHERS;
}
return 0;
}
My problem is that I set the adapter to the recyclerview when the cursor is loaded inside the onLoadFinished method of the CursorLoader and the "dividerSize" method seems to get called before the cursor is loaded setting the default divider to all items.
@Override
public int dividerSize(int position, RecyclerView parent) {
switch (getItemViewType(position)) {
case VIEW_TYPE_ME:
Utils.convertDpToPixel(context.getResources().getDimension(R.dimen.divider_chat_normal), context);
break;
case VIEW_TYPE_OTHERS:
Utils.convertDpToPixel(context.getResources().getDimension(R.dimen.divider_chat_normal), context);
break;
case VIEW_TYPE_OTHERS_BIS:
Utils.convertDpToPixel(context.getResources().getDimension(R.dimen.divider_chat_bis), context);
break;
}
return Utils.convertDpToPixel(context.getResources().getDimension(R.dimen.divider_chat_normal), context);
}
I've tried to call addItemDecoration after the data is loaded into the cursor with no luck.
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
messagesChatAdapter.swapCursor(data);
recyclerView.scrollToPosition(messagesChatAdapter.getItemCount() - 1);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity())
.sizeProvider(messagesChatAdapter)
.color(android.R.color.transparent)
.build());
}
VerticalDividerItemDecoration does not work collectly.
here is my codes:
recyclerView.addItemDecoration(new VerticalDividerItemDecoration.Builder(this)
.margin(50, 50)
.color(Color.BLUE)
.size(30)
.build());
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this)
.margin(50, 50)
.color(Color.YELLOW)
.size(30)
.build());
but the result seems incorrect!
short of vertical color draw,as the following:
Hi,
I'm using an ItemAnimator with an Horizontal LinearLayoutManager. When I call notifyItemRemoved or notifyItemInserted the drawers are not drawn until I scroll to new items. It seems related to this issue https://code.google.com/p/android/issues/detail?id=100653
Could it be possible to fix it?
Thanks !
Unable to set the setPaddingRelative () property when SDK > = 17 sets
When using Java, the API is pretty much self explanatory:
ItemDecoration dividerDecoration = HorizontalDividerItemDecoration.Builder(this)
.sizeResId(R.dimen.item_divider_height)
.visibilityProvider(new VisibilityProvider() {
@Override
boolean shouldHideDivider(int position, RecyclerView parent) {
// With the context of having the method name shown above, this is
// obviously wrong.
return true;
}
}
.build();
However, because VisibilityProvider
is a SAM-type, Kotlin allows you to use a trailing closure, so the name of the method isn't shown anywhere. In this case, a user's first instinct might be to return true
to show the divider and false
to hide it (like I did), which is backwards:
val dividerDecoration = HorizontalDividerItemDecoration.Builder(this)
.sizeResId(R.dimen.item_divider_height)
.visibilityProvider { position, parent ->
// This looked right to me (visibility -> true), but is backwards.
true
}
.build()
I'd suggest inverting that API so it's more Kotlin-friendly:
interface VisibilityProvider {
boolean shouldShowDivider(int position, RecyclerView parent);
}
This issue may apply to other APIs, but I haven't run into any others yet, or had time to look.
The last divider is actually shown permanently, if the recycler view initialized with >1 columns (table-like).
Is it left out on purpose?
I have some headers, but the divider display the top also.
I'm not good at English……
hi bud, u missed calling build() in ur sample code in readme
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview); recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this))
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.drawable.Drawable.getIntrinsicHeight()' on a null object reference
at com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration.getDividerSize(HorizontalDividerItemDecoration.java:90)
at com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration.setItemOffsets(HorizontalDividerItemDecoration.java:79)
at com.yqritc.recyclerviewflexibledivider.FlexibleDividerDecoration.getItemOffsets(FlexibleDividerDecoration.java:158)
at android.support.v7.widget.RecyclerView.getItemDecorInsetsForChild(RecyclerView.java:4489)
at android.support.v7.widget.RecyclerView$LayoutManager.measureChildWithMargins(RecyclerView.java:8443)
The above exception is thrown when the decoration is used with a dialog , i'll copy the style I used below:
<style name="NoFrameDialog" parent="@style/AppTheme.Dialog">
<item name="android:windowBackground">@null</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
I also checked it happens when using no dialog style so it's a matter of using the decoration with a recyclerview in a DialogFragment
I'm using radio buttons in my cells in a horizontal linear layout.
I noticed that when calling notifyItemChanged on two cells at the same time, one to uncheck the radio button and one to check the radio button. That the dividers flash and glitch weirdly.
The above can be worked around by calling notifyDataSetChanged(). But the same problem occurs when calling notifyItemRemoved and notifyItemChanged at the same time which I haven't been able to work around whilst still getting the removed animation.
Thanks,
Tom
Example project
https://github.com/Sylapse/DividerSample.git
Hi,
I use the API as the doc says:
recyclerView.addItemDecoration( new HorizontalDividerItemDecoration.Builder(this) .color(Color.RED) .sizeResId(R.dimen.divider) .marginResId(R.dimen.leftmargin, R.dimen.rightmargin) .build());
However, I find that the color that shows is not the same as that it should be.
Could you please help me out?
Method(com.yqritc.recyclerviewflexibledivider.FlexibleDividerDecoration#getGroupIndex )
calls frequently, and that method consume too much time, ui thread do too much.
GridLayoutManager.SpanSizeLookup#getSpanGroupIndex(int, int) .
https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.SpanSizeLookup.html?hl=ja#getSpanGroupIndex(int;
public int getSpanGroupIndex(int adapterPosition, int spanCount) {
int span = 0;
int group = 0;
int positionSpanSize = getSpanSize(adapterPosition);
for (int i = 0; i < adapterPosition; i++) {
int size = getSpanSize(i);
span += size;
if (span == spanCount) {
span = 0;
group++;
} else if (span > spanCount) {
// did not fit, moving to next row / column
span = size;
group++;
}
}
if (span + positionSpanSize > spanCount) {
group++;
}
return group;
}
Please dont't frequently use method GridLayoutManager.SpanSizeLookup#getSpanGroupIndex(int, int) .
I do it ,and ui thread is good for show.
import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ItemDecoration;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
public class ListSpacingDecoration extends ItemDecoration {
private static final String TAG = ListSpacingDecoration.class.getSimpleName();
private static final int VERTICAL = OrientationHelper.VERTICAL;
private int orientation = -1;
private int spanCount = -1;
private int spacing;
private int halfSpacing;
public ListSpacingDecoration(int spacing) {
super();
this.spacing = spacing;
this.halfSpacing = spacing / 2;
}
/**
* 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator
*/
@Override
public void getItemOffsets(Rect outRect, final View view, RecyclerView parent, State state) {
// super.getItemOffsets(outRect, view, parent, state);
if (orientation == -1) {
orientation = getOrientation(parent);
}
if (spanCount == -1) {
spanCount = getTotalSpan(parent);
}
int childCount = parent.getLayoutManager().getItemCount();
int childIndex = parent.getChildAdapterPosition(view);
int itemSpanSize = getItemSpanSize(parent, childIndex);
int spanIndex = getItemSpanIndex(parent, childIndex);
// LogUtils.d(TAG, "getItemOffsets childCount = " + childCount + " - childIndex = " + childIndex + " : itemSpanSize = "
// + itemSpanSize + " : spanIndex = " + spanIndex);
/* INVALID SPAN */
if (spanCount < 1)
return;
setSpacings(outRect, parent, childCount, childIndex, itemSpanSize, spanIndex);
}
/**
* onDraw方法先于drawChildren
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, State state) {
// TODO
super.onDraw(c, parent, state);
}
/**
* onDrawOver在drawChildren之后,一般我们选择复写其中一个即可
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
// TODO
super.onDrawOver(c, parent, state);
}
protected void setSpacings(Rect outRect, RecyclerView parent, int childCount, int childIndex, int itemSpanSize,
int spanIndex) {
outRect.top = halfSpacing;
outRect.bottom = halfSpacing;
outRect.left = halfSpacing;
outRect.right = halfSpacing;
if (isTopEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.top = spacing;
}
if (isLeftEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
// outRect.left = spacing;
outRect.left = 0;
}
if (isRightEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
// outRect.right = spacing;
outRect.right = 0;
}
if (isBottomEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.bottom = spacing;
}
}
@SuppressWarnings("all")
protected int getTotalSpan(RecyclerView parent) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanCount();
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager) mgr).getSpanCount();
} else if (mgr instanceof LinearLayoutManager) {
return 1;
}
return -1;
}
@SuppressWarnings("all")
protected int getItemSpanSize(RecyclerView parent, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanSize(childIndex);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return 1;
} else if (mgr instanceof LinearLayoutManager) {
return 1;
}
return -1;
}
@SuppressWarnings("all")
protected int getItemSpanIndex(RecyclerView parent, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanIndex(childIndex, spanCount);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return childIndex % spanCount;
} else if (mgr instanceof LinearLayoutManager) {
return 0;
}
return -1;
}
@SuppressWarnings("all")
protected int getOrientation(RecyclerView parent) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof LinearLayoutManager) {
return ((LinearLayoutManager) mgr).getOrientation();
} else if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getOrientation();
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager) mgr).getOrientation();
}
return VERTICAL;
}
protected boolean isLeftEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return spanIndex == 0;
} else {
return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
}
}
protected boolean isRightEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return (spanIndex + itemSpanSize) == spanCount;
} else {
return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
}
}
protected boolean isTopEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
} else {
return spanIndex == 0;
}
}
protected boolean isBottomEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
} else {
return (spanIndex + itemSpanSize) == spanCount;
}
}
protected boolean isFirstItemEdgeValid(boolean isOneOfFirstItems, RecyclerView parent, int childIndex) {
int totalSpanArea = 0;
if (isOneOfFirstItems) {
for (int i = childIndex; i >= 0; i--) {
totalSpanArea = totalSpanArea + getItemSpanSize(parent, i);
}
}
return isOneOfFirstItems && totalSpanArea <= spanCount;
}
protected boolean isLastItemEdgeValid(boolean isOneOfLastItems, RecyclerView parent, int childCount, int childIndex,
int spanIndex) {
int totalSpanRemaining = 0;
if (isOneOfLastItems) {
for (int i = childIndex; i < childCount; i++) {
totalSpanRemaining = totalSpanRemaining + getItemSpanSize(parent, i);
}
}
return isOneOfLastItems && (totalSpanRemaining <= spanCount - spanIndex);
}
}
hi, thanks in advance for your library. recently google released the new androix libraries (AKA support libraries) i will be great if you update the lib dependencies to this news libraries
I encountered a little wierd problem, with this lib.
It works perfectly with any other api version I tried, but with api 21 it "disables" the drag&drop functionality.
In ItemTouchHelper class, there is a method, called "moveIfNecessary", it always returns on the first condition, therefore onMove never get called.
I tried different support versions too.
The lib use some API(getAlpha
,getTranslationX()
,getTranslationY()
) don't support in api 9.
It seem don't support for headerDivider but footerDivider.
hi,i read the readme and import like this.
repositories {
jcenter()
}
dependencies {
compile 'com.yqritc:recyclerview-flexibledivider:1.2.3'
}
but it always fail like this.
Error:(40, 13) Failed to resolve: com.yqritc:recyclerview-flexibledivider:1.2.3
just install sample project. Run on an emulator. Open Memory Monitor. Scroll up and down with several times. Memory is growing. Sometimes GC start, but cannot release more memory. Always call GC.
Any idea on this issue?
Thanks
RemoveItemDecoration
not work !
ItemDecoration = new VerticalDividerItemDecoration.Builder(Context) .color(Color) .size(Size) .build(); recyclerView.addItemDecoration(ItemDecoration );
recyclerView.removeItemDecoration(ItemDecoration);
Failed to resolve: com.yqritc:recyclerview-flexibledivider:1.2.9
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.