效果图
原理
实际上就是绘制一个头部item在
RecycleView
上显示即可,该Item没有随着滑动变动所以看起来就像一个固定的头部。
实现ItemDecoration,重写其
onDraw
、
onDrawOver和
getItemOffsets。
//将decoration绘制到canvas上,会优先于itemView进行绘制,所以超出绘制区域会被itemView覆盖,不会有影响(可以理解为绘制背景)
public void onDraw(Canvas c, RecyclerView parent, State state);
//作用同onDraw,但是晚于itemView的绘制,所以会覆盖在recycleView之上,是完整可见的(不超出 RecycleView 的情况下)
public void onDrawOver(Canvas c, RecyclerView parent, State state);
//将这个方法中获取的outRect插到padding或者margin中,扩大了itemView之间的间距,用于onDraw中绘制decoration
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state);
具体
class StickItemDecoration(var groupInterface: GroupInterface?) : ItemDecoration() {
private var paint: Paint? = null
init {
paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint?.color = Color.RED
paint?.style = Paint.Style.FILL
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val index = parent.getChildAdapterPosition(view)
groupInterface?.let {
if(groupInterface!!.isFirst(index)){
outRect.set(0, 100, 0, 0)
return
}
}
outRect.set(0, 5, 0, 0)
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
val childCount = parent.childCount
for (i in 0 until childCount){
val view = parent.getChildAt(i)
val index = parent.getChildAdapterPosition(view)
if(groupInterface != null && groupInterface!!.isFirst(index)){
paint?.let {
it.color = Color.BLUE
c.drawRect(view.left.toFloat(), (view.top - 100).toFloat(), view.right.toFloat(), view.top.toFloat(), it)
it.color = Color.GREEN
it.textSize = 100f
c.drawText(groupInterface!!.getGroupId(index), view.left.toFloat(), view.top.toFloat(), it)
}
} else {
paint?.let {
it.color = Color.TRANSPARENT
c.drawRect(view.left.toFloat(), (view.top - 5).toFloat(), view.right.toFloat(), view.top.toFloat(), it)
}
}
}
}
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)
val firstVisibleView = parent.getChildAt(0)
val firstVisbleIndex = parent.getChildAdapterPosition(firstVisibleView)
val firstVisbleGroupId = groupInterface?.getGroupId(firstVisbleIndex)
if(firstVisibleView != null && firstVisibleView.top < 100){
paint?.let {
it.color = Color.BLUE
c.drawRect(parent.left.toFloat(), 0f, parent.right.toFloat(), 100f, it)
it.color = Color.GREEN
c.drawText(firstVisbleGroupId, parent.left.toFloat(), 100f, it)
}
}
}
}
interface GroupInterface{
fun isFirst(index: Int): Boolean
fun getGroupId(index: Int): String
}
data class GroupItem(var content: String, var isFirst: Boolean, var groupId: String)
使用
recyclerView.addItemDecoration(StickItemDecoration(object: GroupInterface{
override fun isFirst(index: Int): Boolean {
return dataSource.get(index).isFirst
}
override fun getGroupId(index: Int): String {
return dataSource.get(index).groupId
}
}))