-
-
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); | |
| } | |
| } | |
| } | |
| } |
works perfect
Thanks! Can we use the code in commercial apps?
Thanks a lot!!!
Thanks! Can we use the code in commercial apps?
Sure. :)
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

We add the
mIsShowInLastItemvariable to control the logic of showing divider in last item.