需求分析
如圖所示的:
101(共2人)
這一行, 頂部有 一塊白色區域, 可以當做是分割線101(共2人)
這一行, 底部有一個很細的分割線, 差不多撐滿了一行人物信息
這一行, 首次出現時, 只有底部有分割線, 而且還是 非撐滿一行的效果人物信息
這一行, 最後出現時, 底部沒有分割線
不出意外, 很多同學的實現方式, 都是在 佈局的xml
中, 用padding
maring
backgroud
實現.
但是遇到這種相同type類型的item, 只有中間有分割線, 最後一條沒有分割線
的情況, 估計就有點棘手了.
莫慌, 看完本文, 你能輕鬆應對各種噁心的分割線.
具體實現
繼承 RecyclerView.ItemDecoration
, 實現 核心的 getItemOffsets
onDraw
onDrawOver
方法, 通常 只需要實現 getItemOffsets
onDraw
即可. 如果需要懸停效果, 才需要實現 onDrawOver
爲了讓封裝更輕量
, 所以, 我並打算有任何實際操作方法.
只做核心業務的封裝, 具體實現 丟給調用者.
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
eachChildViewHolder(parent) { beforeViewHolder, viewHolder, afterViewHolder ->
eachItemDoIt.invoke(canvas, parent, state, null, beforeViewHolder, viewHolder, afterViewHolder, false)
}
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
eachChildViewHolder(parent, view) { beforeViewHolder, viewHolder, afterViewHolder ->
eachItemDoIt.invoke(null, parent, state, outRect, beforeViewHolder, viewHolder, afterViewHolder, false)
}
}
核心方法
fun eachChildViewHolder(
parent: RecyclerView,
targetView: View? = null,/*指定目標, 則只回調目標前後的ViewHolder*/
callback: (
beforeViewHolder: RecyclerView.ViewHolder?,
viewHolder: RecyclerView.ViewHolder,
afterViewHolder: RecyclerView.ViewHolder?
) -> Unit
) {
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val childViewHolder = parent.findContainingViewHolder(child)
childViewHolder?.let {
//前一個child
var beforeViewHolder: RecyclerView.ViewHolder? = null
//後一個child
var afterViewHolder: RecyclerView.ViewHolder? = null
if (i >= 1) {
beforeViewHolder = parent.findContainingViewHolder(parent.getChildAt(i - 1))
}
if (i < childCount - 1) {
afterViewHolder = parent.findContainingViewHolder(parent.getChildAt(i + 1))
}
if (targetView != null) {
if (targetView == child) {
callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
return
}
} else {
callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
}
}
}
}
通過此方法, 到RecyclerView
觸發onDraw
時, 枚舉界面上的所有childView
, 並且計算拿到 前一個
和 後一個
childView
的viewHolder
對象.(如果有)
這樣就可以通過 ViewHolder.getItemViewType
來區分, 各個item
的類型, 也能夠通過,
與前一個
比較, 判斷是否是同類型的第一個位置
與後一個
比較, 判斷是否是同類型的最後一個位置
有個你想要的各種信息, 繪製分割線的事, 就交給 canvas
吧.
完整代碼
class DslItemDecoration : RecyclerView.ItemDecoration() {
val paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
val tempDrawRect = Rect()
/**
* 將3個方法, 合一調用. 通過參數, 來區分是那一個方法.
*
* outRect 不爲空時, 是 getItemOffsets 方法
* canvas 不爲空時, 是 onDrawOver onDraw
* isOverDraw 控制是否是 onDrawOver
* */
var eachItemDoIt: (
canvas: Canvas?, parent: RecyclerView, state: RecyclerView.State, outRect: Rect?,
beforeViewHolder: RecyclerView.ViewHolder?,
viewHolder: RecyclerView.ViewHolder,
afterViewHolder: RecyclerView.ViewHolder?,
isOverDraw: Boolean
) -> Unit =
{ _, _, _, _, _, _, _, _ -> }
override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
eachChildRViewHolder(parent) { beforeViewHolder, viewHolder, afterViewHolder ->
eachItemDoIt.invoke(canvas, parent, state, null, beforeViewHolder, viewHolder, afterViewHolder, true)
}
}
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
eachChildRViewHolder(parent) { beforeViewHolder, viewHolder, afterViewHolder ->
eachItemDoIt.invoke(canvas, parent, state, null, beforeViewHolder, viewHolder, afterViewHolder, false)
}
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
eachChildRViewHolder(parent, view) { beforeViewHolder, viewHolder, afterViewHolder ->
eachItemDoIt.invoke(null, parent, state, outRect, beforeViewHolder, viewHolder, afterViewHolder, false)
}
}
fun eachChildViewHolder(
parent: RecyclerView,
targetView: View? = null,/*指定目標, 則只回調目標前後的ViewHolder*/
callback: (
beforeViewHolder: RecyclerView.ViewHolder?,
viewHolder: RecyclerView.ViewHolder,
afterViewHolder: RecyclerView.ViewHolder?
) -> Unit
) {
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val childViewHolder = parent.findContainingViewHolder(child)
childViewHolder?.let {
//前一個child
var beforeViewHolder: RecyclerView.ViewHolder? = null
//後一個child
var afterViewHolder: RecyclerView.ViewHolder? = null
if (i >= 1) {
beforeViewHolder = parent.findContainingViewHolder(parent.getChildAt(i - 1))
}
if (i < childCount - 1) {
afterViewHolder = parent.findContainingViewHolder(parent.getChildAt(i + 1))
}
if (targetView != null) {
if (targetView == child) {
callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
return
}
} else {
callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
}
}
}
}
}
調用例子
public fun RecyclerView.dslItemDecoration(init: DslItemDecoration.() -> Unit) {
addItemDecoration(DslItemDecoration().apply {
init()
})
}
dslItemDecoration {
val line = getDimen(R.dimen.wt_line)
eachItemDoIt = { canvas, _, _, outRect, _, viewHolder, afterViewHolder, _ ->
if (viewHolder.itemViewType == R.layout.item_info_group_head) {
outRect?.set(0, 10 * dpi, 0, line)
tempDrawRect.set(
0,
viewHolder.itemView.top - 10 * dpi,
viewHolder.itemView.right,
viewHolder.itemView.top
)
paint.color = getColor(R.color.wt_dark_bg)
canvas?.drawRect(tempDrawRect, paint)
tempDrawRect.set(
0,
viewHolder.itemView.top - line,
viewHolder.itemView.right,
viewHolder.itemView.top
)
paint.color = getColor(R.color.wt_line)
canvas?.drawRect(tempDrawRect, paint)
tempDrawRect.set(
0,
viewHolder.itemView.bottom,
viewHolder.itemView.right,
viewHolder.itemView.bottom - line
)
canvas?.drawRect(tempDrawRect, paint)
} else if (viewHolder.itemViewType == R.layout.item_info_single_text) {
if (afterViewHolder?.itemViewType == R.layout.item_info_single_text) {
outRect?.set(0, 0, 0, line)
paint.color = getColor(R.color.wt_line)
tempDrawRect.set(
25 * dpi,
viewHolder.itemView.bottom,
viewHolder.itemView.right,
viewHolder.itemView.bottom - line
)
canvas?.drawRect(tempDrawRect, paint)
}
}
}
}
結束…
羣內有各(pian)種(ni)各(jin)樣(qun)
的大佬,等你來撩.
聯繫作者
請使用QQ掃碼加羣, 小夥伴們都在等着你哦!
關注我的公衆號, 每天都能一起玩耍哦!