-
-
Save Veeyikpong/a376c6128e603b0dee316670a74b345b to your computer and use it in GitHub Desktop.
| /* | |
| * Copyright 2018 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 androidx.recyclerview.widget | |
| import android.content.Context | |
| import android.graphics.Canvas | |
| import android.graphics.Rect | |
| import android.graphics.drawable.Drawable | |
| import android.util.Log | |
| import android.view.View | |
| import android.widget.LinearLayout | |
| import android.graphics.PorterDuff | |
| import android.graphics.PorterDuffColorFilter | |
| /** | |
| * MiddleDividerItemDecoration is a [RecyclerView.ItemDecoration] that can be used as a divider | |
| * between items of a [LinearLayoutManager]. It supports both [.HORIZONTAL] and | |
| * [.VERTICAL] orientations. | |
| * It can also supports [.ALL], included both the horizontal and vertical. Mainly used for GridLayout. | |
| * <pre> | |
| * For normal usage with LinearLayout, | |
| * val mItemDecoration = MiddleDividerItemDecoration(context!!,DividerItemDecoration.VERTICAL) | |
| * For GridLayoutManager with inner decorations, | |
| * val mItemDecoration = MiddleDividerItemDecoration(context!!,MiddleDividerItemDecoration.ALL) | |
| * recyclerView.addItemDecoration(mItemDecoration); | |
| </pre> * | |
| */ | |
| class MiddleDividerItemDecoration | |
| /** | |
| * Creates a divider [RecyclerView.ItemDecoration] that can be used with a | |
| * [LinearLayoutManager]. | |
| * | |
| * @param context Current context, it will be used to access resources. | |
| * @param orientation Divider orientation. Should be [.HORIZONTAL] or [.VERTICAL]. | |
| */ | |
| (context: Context, orientation: Int) : RecyclerView.ItemDecoration() { | |
| private var mDivider: Drawable? = null | |
| /** | |
| * Current orientation. Either [.HORIZONTAL] or [.VERTICAL]. | |
| */ | |
| private var mOrientation: Int = 0 | |
| private val mBounds = Rect() | |
| init { | |
| val 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) | |
| } | |
| fun setDividerColor(color: Int) { | |
| mDivider!!.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP) | |
| } | |
| /** | |
| * Sets the orientation for this divider. This should be called if | |
| * [RecyclerView.LayoutManager] changes orientation. | |
| * | |
| * @param orientation [.HORIZONTAL] or [.VERTICAL] | |
| */ | |
| fun setOrientation(orientation: Int) { | |
| if (orientation != HORIZONTAL && orientation != VERTICAL && orientation != ALL) { | |
| throw IllegalArgumentException( | |
| "Invalid orientation. It should be either HORIZONTAL or VERTICAL" | |
| ) | |
| } | |
| mOrientation = orientation | |
| } | |
| /** | |
| * Sets the [Drawable] for this divider. | |
| * | |
| * @param drawable Drawable that should be used as a divider. | |
| */ | |
| fun setDrawable(drawable: Drawable) { | |
| if (drawable == null) { | |
| throw IllegalArgumentException("Drawable cannot be null.") | |
| } | |
| mDivider = drawable | |
| } | |
| override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { | |
| if (parent.layoutManager == null || mDivider == null) { | |
| return | |
| } | |
| when (mOrientation) { | |
| ALL -> { | |
| drawVertical(c, parent) | |
| drawHorizontal(c, parent) | |
| } | |
| VERTICAL -> drawVertical(c, parent) | |
| else -> drawHorizontal(c, parent) | |
| } | |
| } | |
| private fun drawVertical(canvas: Canvas, parent: RecyclerView) { | |
| canvas.save() | |
| val left: Int | |
| val right: Int | |
| if (parent.clipToPadding) { | |
| left = parent.paddingLeft | |
| right = parent.width - parent.paddingRight | |
| canvas.clipRect( | |
| left, parent.paddingTop, right, | |
| parent.height - parent.paddingBottom | |
| ) | |
| } else { | |
| left = 0 | |
| right = parent.width | |
| } | |
| var childCount = parent.childCount | |
| if (parent.layoutManager is GridLayoutManager) { | |
| var leftItems = childCount % (parent.layoutManager as GridLayoutManager).spanCount | |
| if (leftItems == 0) { | |
| leftItems = (parent.layoutManager as GridLayoutManager).spanCount | |
| } | |
| //Identify last row, and don't draw border for these items | |
| childCount -= leftItems | |
| } | |
| for (i in 0 until childCount - 1) { | |
| val child = parent.getChildAt(i) ?: return | |
| parent.getDecoratedBoundsWithMargins(child, mBounds) | |
| val bottom = mBounds.bottom + Math.round(child.translationY) | |
| val top = bottom - mDivider!!.intrinsicHeight | |
| mDivider!!.setBounds(left, top, right, bottom) | |
| mDivider!!.draw(canvas) | |
| } | |
| canvas.restore() | |
| } | |
| private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) { | |
| canvas.save() | |
| val top: Int | |
| val bottom: Int | |
| if (parent.clipToPadding) { | |
| top = parent.paddingTop | |
| bottom = parent.height - parent.paddingBottom | |
| canvas.clipRect( | |
| parent.paddingLeft, top, | |
| parent.width - parent.paddingRight, bottom | |
| ) | |
| } else { | |
| top = 0 | |
| bottom = parent.height | |
| } | |
| var childCount = parent.childCount | |
| if (parent.layoutManager is GridLayoutManager) { | |
| childCount = (parent.layoutManager as GridLayoutManager).spanCount | |
| } | |
| for (i in 0 until childCount - 1) { | |
| val child = parent.getChildAt(i) ?: return | |
| parent.layoutManager!!.getDecoratedBoundsWithMargins(child, mBounds) | |
| val right = mBounds.right + Math.round(child.translationX) | |
| val left = right - mDivider!!.intrinsicWidth | |
| mDivider!!.setBounds(left, top, right, bottom) | |
| mDivider!!.draw(canvas) | |
| } | |
| canvas.restore() | |
| } | |
| override fun getItemOffsets( | |
| outRect: Rect, view: View, parent: RecyclerView, | |
| state: RecyclerView.State | |
| ) { | |
| if (mDivider == null) { | |
| outRect.set(0, 0, 0, 0) | |
| return | |
| } | |
| if (mOrientation == VERTICAL) { | |
| outRect.set(0, 0, 0, mDivider!!.intrinsicHeight) | |
| } else { | |
| outRect.set(0, 0, mDivider!!.intrinsicWidth, 0) | |
| } | |
| } | |
| companion object { | |
| val HORIZONTAL = LinearLayout.HORIZONTAL | |
| val VERTICAL = LinearLayout.VERTICAL | |
| //mainly used for GridLayoutManager | |
| val ALL = 2 | |
| private val TAG = "DividerItem" | |
| private val ATTRS = intArrayOf(android.R.attr.listDivider) | |
| } | |
| } |
Hi, It looks good. Please create a Java version as well.
Hi, I had to use your gist code in java.
So I converted your code from kotlin to java and It works well.
How I could share the translation version of your code in java?
I've attached my code below.
https://gist.github.com/nuovothoth/ed8f3952e90a5c4ed263ad1480382522
Hi @nuovothoth thanks for the help to translate.
You can share your gist to Stackoverflow on your own. I will help to include in my medium post also. (https://medium.com/p/6ba48d13bf16)
Thank you.
Hi,
Thanks for your sample of ItemDecoration.
I see a little bug. The ALL case is forgotten in getItemOffsets.
You can replace :
if (mOrientation == VERTICAL) { outRect.set(0, 0, 0, mDivider!!.intrinsicHeight) } else { outRect.set(0, 0, mDivider!!.intrinsicWidth, 0) }
by
when (mOrientation) { ALL -> { outRect.set(0, 0, mDivider!!.intrinsicWidth, mDivider!!.intrinsicHeight) } VERTICAL -> {outRect.set(0, 0, 0, mDivider!!.intrinsicHeight) } else -> { outRect.set(0, 0, mDivider!!.intrinsicWidth, 0) } }
This is a very cool solution. Thanks a lot.
var childCount = parent.childCount
if (parent.layoutManager is GridLayoutManager) {
childCount = (parent.layoutManager as GridLayoutManager).spanCount
}
for (i in 0 until childCount - 1) {
val child = parent.getChildAt(i)
Here will NPE when children count is small than span count, shoud change to
for (i in 0 until (childCount - 1).coerceAtMost(parent.childCount)) {
val child = parent.getChildAt(i)
Sample usage
GridLayoutManager
LInearLayoutManager
You can also set the divider color with setDividerColor