Я попытался написать собственный класс DividerItemDecoration
, который позволяет мне указать, где нарисованы разделители.
Я хотел, чтобы он поддерживал четыре случая:
TOP
: рисовать разделители на верхней стороне элемента recyclerview (включая верх первого элемента). BOTTOM
: рисовать разделители на нижней стороне элемента recyclerview (включая нижнюю часть последнего элемента) ). (вот как androidx.recyclerview.widget.DividerItemDecoration уже делает это.) ONLYBETWEEN
: рисовать разделители только между элементами recyclerview (не будет разделитель над первым элементом, и не будет разделителя ниже последнего элемента). EVERYWHERE
: нарисуйте разделители везде (разделитель должен быть выше первого элемента, между каждым другим элементом и ниже последний элемент).
Первые два потенциально могут быть опущены, потому что очень легко создать аналогичный эффект, используя макеты XML.
Если у вас есть класс который уже поддерживает эти вещи, я бы тоже принял их как ответ. Но поскольку я ничего не нашел сам, я решил попробовать создать свой собственный класс.
В настоящее время мой CustomDividerItemDecoration
класс выглядит так:
import android.content.Context
import android.content.res.TypedArray
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 androidx.recyclerview.widget.RecyclerView
import kotlin.math.roundToInt
class CustomDividerItemDecoration(
context: Context,
orientation: Int,
private val dividerPosition: DividerPositions
) : RecyclerView.ItemDecoration() {
enum class DividerPositions {
ONLYBETWEEN, BOTTOM, TOP, START, END, EVERYWHERE
}
companion object {
private const val TAG = "CustomDividerItem"
private val ATTRS = intArrayOf(android.R.attr.listDivider)
}
var mDivider: Drawable?
var mOrientation: Int = orientation
private val mBounds = Rect()
init {
val a: TypedArray = 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()
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.layoutManager == null || mDivider == null) {
return
}
if (mOrientation == LinearLayout.VERTICAL) {
drawVertical(c, parent)
} else if (mOrientation == LinearLayout.HORIZONTAL) {
drawHorizontal(c, parent)
}
}
private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val left: Int
val right: Int
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
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
}
val childCount = parent.childCount
for (i in 0 until childCount) {
when (dividerPosition) {
DividerPositions.BOTTOM -> {
val child = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, mBounds)
val bottom = mBounds.bottom + child.translationY.roundToInt()
val top = bottom - mDivider!!.intrinsicHeight
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
DividerPositions.TOP -> {
//this doesn't work
val child = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, mBounds)
val top = mBounds.top + child.translationY.roundToInt()
val bottom = top + mDivider!!.intrinsicHeight
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
DividerPositions.EVERYWHERE -> {
TODO()
}
DividerPositions.ONLYBETWEEN -> {
TODO()
}
else -> {
throw IllegalStateException("Can't draw dividers in position ${dividerPosition.name} while drawing vertical.")
}
}
}
canvas.restore()
}
private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val top: Int
val bottom: Int
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
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
}
val childCount = parent.childCount
for (i in 0 until childCount) {
when (dividerPosition) {
DividerPositions.END -> {
val child = parent.getChildAt(i)
parent.layoutManager?.getDecoratedBoundsWithMargins(child, mBounds)
val right = mBounds.right + child.translationX.roundToInt()
val left = right - mDivider!!.intrinsicWidth
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
DividerPositions.START -> {
//this doesn't work.
val child = parent.getChildAt(i)
parent.layoutManager?.getDecoratedBoundsWithMargins(child, mBounds)
val left = mBounds.left - child.translationX.roundToInt()
val right = left + mDivider!!.intrinsicWidth
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
DividerPositions.EVERYWHERE -> {
TODO()
}
DividerPositions.ONLYBETWEEN -> {
TODO()
}
else -> {
throw IllegalStateException("Can't draw dividers in position ${dividerPosition.name} while drawing horizontal.")
}
}
val child = parent.getChildAt(i)
parent.layoutManager?.getDecoratedBoundsWithMargins(child, mBounds)
val right = mBounds.right + child.translationX.roundToInt()
val left = right - mDivider!!.getIntrinsicWidth()
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 == LinearLayout.VERTICAL) {
outRect.set(0, 0, 0, mDivider!!.getIntrinsicHeight())
} else {
outRect.set(0, 0, mDivider!!.getIntrinsicWidth(), 0)
}
}
}