通过本文你讲了解到: 1.RecyclerView.ItemDecoration的一般写法 2.View的DrawingCache的相关内容 3.Kotlin的简单语法 4.这个一个支持任意分组的,任意布局的Item装饰。外加可以顶部吸附效果(当然你不喜欢,也可以不启用)
灵感来源:(www.jianshu.com/p/b335b620a… ) 先偷一张图,想要的效果就是这样的。
然后是我写的代码的效果:
1.先说说ItemDecoration
ItemDecoration主要一下三个方法,可以给Item添加装饰,这就是装饰器的意思,一般用来做分割线。
public void onDraw(Canvas c, RecyclerView parent, State state)
public void onDrawOver(Canvas c, RecyclerView parent, State state)
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
onDraw是在Item内容之前绘制,onDrawOver是在Item内容之上绘制,getItemOffsets是给Item设置一个偏移量,来给装饰器留下绘制的空间。
再偷一个图:
本次的效果,顶部悬浮的装饰是在onDrawOver中绘制,其他的装饰是在onDraw中绘制,getItemOffsets中判断分组的第一个,设置偏移。
2.然后是DrawingCache
绘制装饰器是先通过cache机制,将装饰器保存为bitmap,然后用canvas绘制上去。
我们要获取cache首先要通过setDrawingCacheEnable方法开启cache,然后再调用getDrawingCache方法就可以获得view的cache图片了。
buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,若果cache没有建立,系统会自动调用buildDrawingCache方法生成cache。因为会更新装饰器的内容, 所以要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的。
当调用setDrawingCacheEnabled方法设置为false, 系统也会自动把原来的cache销毁。
3.最后是代码
package top.greendami.mykotlinapp
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Rect
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
class SectionDecoration<T>(
var context: Context,
var dataList: ArrayList<T>,
val layoutId: Int,
val groupListener: GroupListener,
var isFloat: Boolean = true,
var sectionLayout: ViewGroup = LayoutInflater.from(context).inflate(layoutId, null) as ViewGroup
) : RecyclerView.ItemDecoration() {
var lastBitmap: Bitmap? = null
var firstTop: Int = 0
init {
val layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
sectionLayout.layoutParams = layoutParams
sectionLayout.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
}
//绘制分割区域
override fun onDraw(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
super.onDraw(c, parent, state)
val left = parent!!.paddingLeft
for (i: Int in 0..parent.childCount) {
if (parent.getChildAdapterPosition(parent.getChildAt(i)) != -1) {
//设置内容
groupListener.setContnt(
sectionLayout,
parent.getChildAdapterPosition(parent.getChildAt(i))
)
//设置内容后重新测量(此处默认父布局宽度)
sectionLayout.measure(
View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
sectionLayout.layout(
0,
0,
parent.width - parent.paddingRight,
sectionLayout.measuredHeight
)
sectionLayout.isDrawingCacheEnabled = true
sectionLayout.buildDrawingCache(true)
c!!.drawBitmap(
sectionLayout.drawingCache,
left.toFloat(),
(parent.getChildAt(i).top - sectionLayout.measuredHeight).toFloat(),
null
)
//获取图像(保存滚出屏幕的最后一个)
if ((parent.getChildAt(i).top - sectionLayout.measuredHeight) <= 0) {
lastBitmap = Bitmap.createBitmap(sectionLayout.drawingCache)
}
sectionLayout.destroyDrawingCache()
sectionLayout.isDrawingCacheEnabled = false
} else {
continue
}
}
}
//如果开启了悬浮,绘制悬浮的那个分割区域
override fun onDrawOver(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
super.onDrawOver(c, parent, state)
if (!isFloat) {
return
}
val left = parent!!.paddingLeft
for (i: Int in 0..parent.childCount) {
if (parent.getChildAdapterPosition(parent.getChildAt(i)) != -1 && groupListener.isFirst(parent.getChildAdapterPosition(parent.getChildAt(i)))) {
//parent.getChildAt(i).top是Item内容的高度,不包含Decoration的高度;sectionLayout.measuredHeight是Decoration的高度
if (parent.getChildAt(i).top in sectionLayout.measuredHeight..sectionLayout.measuredHeight * 2) {
firstTop = parent.getChildAt(i).top - sectionLayout.measuredHeight * 2
if(lastBitmap != null){
c!!.drawBitmap(lastBitmap, left.toFloat(), firstTop.toFloat(), null)
}
//发现是交换的过程,绘制完交换后的Decoration后,不再绘制top位置是0的Decoration
return
} else {
firstTop = 0
}
} else {
firstTop = 0
}
}
//绘制top位置是0的Decoration
if(lastBitmap != null){
c!!.drawBitmap(lastBitmap, left.toFloat(), firstTop.toFloat(), null)
}
}
//每个Item给留出分割区域的绘制控件
override fun getItemOffsets(outRect: Rect?, itemPosition: Int, parent: RecyclerView?) {
super.getItemOffsets(outRect, itemPosition, parent)
if (groupListener.isFirst(itemPosition)) {
outRect!!.top = sectionLayout.measuredHeight
}
}
}
abstract class GroupListener {
abstract fun isFirst(position: Int): Boolean
abstract fun setContnt(contentView: ViewGroup, position: Int)
}
```
Github( github.com/GreendaMi/P… )