-
-
Save johnwatsondev/720730cf6b8c59fa6abe4f31dbaf59d7 to your computer and use it in GitHub Desktop.
/* | |
* Copyright (C) 2016 The Android Open Source Project | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package android.support.v7.widget; | |
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.annotation.NonNull; | |
import android.util.Log; | |
import android.view.View; | |
import android.widget.LinearLayout; | |
/** | |
* DividerItemDecoration is a {@link RecyclerView.ItemDecoration} that can be used as a divider | |
* between items of a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and | |
* {@link #VERTICAL} orientations. | |
* | |
* <pre> | |
* mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), | |
* mLayoutManager.getOrientation()); | |
* recyclerView.addItemDecoration(mDividerItemDecoration); | |
* </pre> | |
*/ | |
public class DividerItemDecoration extends RecyclerView.ItemDecoration { | |
public static final int HORIZONTAL = LinearLayout.HORIZONTAL; | |
public static final int VERTICAL = LinearLayout.VERTICAL; | |
private static final String TAG = "DividerItem"; | |
private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; | |
private Drawable mDivider; | |
/** | |
* Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}. | |
*/ | |
private int mOrientation; | |
// private final Rect mBounds = new Rect(); | |
private final boolean mIsShowInLastItem; | |
/** | |
* Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a | |
* {@link LinearLayoutManager}. | |
* | |
* @param context Current context, it will be used to access resources. | |
* @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}. | |
* @param isShowInLastItem Whether show the divider in last item. | |
*/ | |
public DividerItemDecoration(Context context, int orientation, boolean isShowInLastItem) { | |
final TypedArray a = context.obtainStyledAttributes(ATTRS); | |
mDivider = a.getDrawable(0); | |
if (mDivider == null) { | |
Log.w(TAG, "@android:attr/listDivider was not set in the theme used for this " | |
+ "DividerItemDecoration. Please set that attribute all call setDrawable()"); | |
} | |
a.recycle(); | |
setOrientation(orientation); | |
this.mIsShowInLastItem = isShowInLastItem; | |
} | |
/** | |
* Sets the orientation for this divider. This should be called if | |
* {@link RecyclerView.LayoutManager} changes orientation. | |
* | |
* @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} | |
*/ | |
public void setOrientation(int orientation) { | |
if (orientation != HORIZONTAL && orientation != VERTICAL) { | |
throw new IllegalArgumentException( | |
"Invalid orientation. It should be either HORIZONTAL or VERTICAL"); | |
} | |
mOrientation = orientation; | |
} | |
/** | |
* Sets the {@link Drawable} for this divider. | |
* | |
* @param drawable Drawable that should be used as a divider. | |
*/ | |
public void setDrawable(@NonNull Drawable drawable) { | |
if (drawable == null) { | |
throw new IllegalArgumentException("Drawable cannot be null."); | |
} | |
mDivider = drawable; | |
} | |
@Override | |
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { | |
if (parent.getLayoutManager() == null || mDivider == null) { | |
return; | |
} | |
if (mOrientation == VERTICAL) { | |
drawVertical(c, parent); | |
} else { | |
drawHorizontal(c, parent); | |
} | |
} | |
private void drawVertical(Canvas canvas, RecyclerView parent) { | |
canvas.save(); | |
final int left; | |
final int right; | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && parent.getClipToPadding()) { | |
left = parent.getPaddingLeft(); | |
right = parent.getWidth() - parent.getPaddingRight(); | |
canvas.clipRect(left, parent.getPaddingTop(), right, | |
parent.getHeight() - parent.getPaddingBottom()); | |
} else { | |
left = 0; | |
right = parent.getWidth(); | |
} | |
int childCount; | |
if (mIsShowInLastItem) { | |
childCount = parent.getChildCount(); | |
} else { | |
childCount = parent.getChildCount() - 1; | |
} | |
for (int i = 0; i < childCount; i++) { | |
final View child = parent.getChildAt(i); | |
// parent.getDecoratedBoundsWithMargins(child, mBounds); | |
// final int bottom = mBounds.bottom + Math.round(child.getTranslationY()); | |
int decoratedBottom = parent.getLayoutManager().getDecoratedBottom(child); | |
final int bottom = decoratedBottom + Math.round(child.getTranslationY()); | |
final int top = bottom - mDivider.getIntrinsicHeight(); | |
mDivider.setBounds(left, top, right, bottom); | |
mDivider.draw(canvas); | |
} | |
canvas.restore(); | |
} | |
private void drawHorizontal(Canvas canvas, RecyclerView parent) { | |
canvas.save(); | |
final int top; | |
final int bottom; | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && parent.getClipToPadding()) { | |
top = parent.getPaddingTop(); | |
bottom = parent.getHeight() - parent.getPaddingBottom(); | |
canvas.clipRect(parent.getPaddingLeft(), top, | |
parent.getWidth() - parent.getPaddingRight(), bottom); | |
} else { | |
top = 0; | |
bottom = parent.getHeight(); | |
} | |
int childCount; | |
if (mIsShowInLastItem) { | |
childCount = parent.getChildCount(); | |
} else { | |
childCount = parent.getChildCount() - 1; | |
} | |
for (int i = 0; i < childCount; i++) { | |
final View child = parent.getChildAt(i); | |
// parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds); | |
// final int right = mBounds.right + Math.round(child.getTranslationX()); | |
int decoratedRight = parent.getLayoutManager().getDecoratedRight(child); | |
final int right = decoratedRight + Math.round(child.getTranslationX()); | |
final int left = right - mDivider.getIntrinsicWidth(); | |
mDivider.setBounds(left, top, right, bottom); | |
mDivider.draw(canvas); | |
} | |
canvas.restore(); | |
} | |
@Override | |
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { | |
if (mDivider == null) { | |
outRect.setEmpty(); | |
return; | |
} | |
int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); | |
int itemCount = state.getItemCount(); | |
if (mIsShowInLastItem) { | |
if (mOrientation == VERTICAL) { | |
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); | |
} else { | |
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); | |
} | |
} else if (itemPosition == itemCount - 1) { | |
// We didn't set the last item when mIsShowInLastItem's value is false. | |
outRect.setEmpty(); | |
} else { | |
if (mOrientation == VERTICAL) { | |
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); | |
} else { | |
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); | |
} | |
} | |
} | |
} |
Thx A lot !!!,, helpfull
thanks!!
I have been using this code for 2 years, but currently noticed that adding a picture can sometimes produce removing a space before the last item (and after the last), if isShowInLastItem == false
. If use DividerItemDecoration
, all spaces will be equal, but we will have the last space visible. I think,
} else if (itemPosition == itemCount - 1) {
// We didn't set the last item when isShowInLastItem's value is false.
outRect.setEmpty();
}
works wrong, but I am not sure. Every time I add a picture before plus sign (in a last but one position).
UPDATE
Sorry, I found a mistake in my code. When I added a picture, I used notifyItemInserted(position)
to update a list. But in my case it was position = list.lastIndex
(this is wrong). So, it made double refreshing and called outRect.setEmpty();
twice. By the way, after removing outRect.setEmpty();
all dividers were drawn the same way.
Thanks @johnwatsondev , I am using this in to Kotlin code and Here i had converted it to Kotlin: https://gist.github.com/bipinvaylu/2714d9d429dc72b0108c05be52b609e0
Sure. :)