直播网站程序源码,FlowLayoutManager 流式布局
import android.graphics.Rect
import android.util.Log
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
class FlowLayoutManager : RecyclerView.LayoutManager() {
companion object {
const val TAG = "FlowLayoutManager2"
}
var widthFlow = 0
var heightFlow = 0
private var left = 0
private var top = 0
private var right = 0
private var useMaxWidth = 0
private var verticalScrollOffset = 0
var totalHeight = 0
private set
private var row = Row()
private val lineRows: MutableList<Row> = mutableListOf()
private val allItemFrames = SparseArray<Rect>()
override fun isAutoMeasureEnabled(): Boolean {
return true
}
override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
return RecyclerView.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
Log.d(TAG, "onLayoutChildren")
totalHeight = 0
var cuLineTop = top
//当前行使用的高度
var cuLineWidth = 0
var itemLeft: Int
var itemTop: Int
var maxHeightItem = 0
row = Row()
lineRows.clear()
allItemFrames.clear()
removeAllViews()
if (itemCount == 0) {
recycler?.let {
detachAndScrapAttachedViews(it)
}
verticalScrollOffset = 0
return
}
if (childCount == 0 && state?.isPreLayout == true) {
return
}
//onLayoutChildren方法在RecyclerView 初始化时 会执行两遍
recycler?.let {
detachAndScrapAttachedViews(it)
}
if (childCount == 0) {
widthFlow = width
heightFlow = height
left = paddingLeft
right = paddingRight
top = paddingTop
useMaxWidth = widthFlow - left - right
}
for (i in 0 until itemCount) {
Log.d(TAG, "index:$i")
val childAt = recycler?.getViewForPosition(i) ?: continue
if (View.GONE == childAt.visibility) {
continue
}
measureChildWithMargins(childAt, 0, 0)
val childWidth = getDecoratedMeasuredWidth(childAt)
val childHeight = getDecoratedMeasuredHeight(childAt)
if ((cuLineWidth + childWidth) <= useMaxWidth) {
itemLeft = left + cuLineWidth
itemTop = cuLineTop
val frame = allItemFrames.get(i) ?: Rect()
frame.set(itemLeft, itemTop, itemLeft + childWidth, itemTop + childHeight)
allItemFrames.put(i, frame)
cuLineWidth += childWidth
maxHeightItem = maxHeightItem.coerceAtLeast(childHeight)
row.views.add(Item(childHeight, childAt, frame))
row.cuTop = cuLineTop
row.maxHeight = maxHeightItem
} else {
// 换行
formatAboveRow()
cuLineTop += maxHeightItem
totalHeight += maxHeightItem
itemTop = cuLineTop
itemLeft = left
val frame = allItemFrames.get(i) ?: Rect()
frame.set(itemLeft, itemTop, itemLeft + childWidth, itemTop + childHeight)
allItemFrames.put(i, frame)
cuLineWidth = childWidth
maxHeightItem = childHeight
row.views.add(Item(childHeight, childAt, frame))
row.cuTop = cuLineTop
row.maxHeight = maxHeightItem
}
//不要忘了最后一行进行刷新下布局
if (i == itemCount - 1) {
formatAboveRow()
totalHeight += maxHeightItem
}
}
totalHeight = totalHeight.coerceAtLeast(getVerticalSpace())
Log.d(TAG, "onLayoutChildren totalHeight:$totalHeight")
fillLayout(state)
}
private fun fillLayout(state: RecyclerView.State?) {
if (state?.isPreLayout == true || itemCount == 0) {
// 跳过preLayout,preLayout主要用于支持动画
return
}
//对所有的行信息进行遍历
for (j in 0 until lineRows.size) {
val row = lineRows[j]
val views = row.views
for (i in 0 until views.size) {
val scrap = views[i].view
measureChildWithMargins(scrap, 0, 0)
addView(scrap)
val frame = views[i].rect
//将这个item布局出来
layoutDecoratedWithMargins(
scrap,
frame.left ,
frame.top - verticalScrollOffset,
frame.right ,
frame.bottom - verticalScrollOffset
)
}
}
}
private fun formatAboveRow() {
var lineNeedWidth = 0
val views = row.views
for (i in 0 until views.size) {
//计算行高居中
val item = views[i]
val view = item.view
val position = getPosition(view)
if (allItemFrames[position].top < row.cuTop + (row.maxHeight - item.useHeight) / 2) {
val frame = allItemFrames[position] ?: Rect()
frame.set(
allItemFrames[position].left,
row.cuTop + (row.maxHeight - item.useHeight) / 2,
allItemFrames[position].right,
row.cuTop + (row.maxHeight - item.useHeight) / 2 + getDecoratedMeasuredHeight(view)
)
allItemFrames.put(position,frame)
item.rect = frame
views[i] = item
}
//计算行宽居中
lineNeedWidth += (item.rect.right - item.rect.left)
}
val off = (useMaxWidth - lineNeedWidth) / 2
for (item in views) {
item.rect.left += off
item.rect.right += off
}
lineRows.add(row)
row = Row()
}
override fun canScrollVertically(): Boolean {
return true
}
override fun scrollVerticallyBy(
dy: Int,
recycler: RecyclerView.Recycler?,
state: RecyclerView.State?
): Int {
return super.scrollVerticallyBy(dy, recycler, state)
}
private fun getVerticalSpace(): Int {
return height - paddingBottom - paddingTop
}
//行信息的定义
class Row(val views: MutableList<Item> = mutableListOf()) {
//每一行的头部坐标
var cuTop: Int = 0
//每一行需要占据的最大高度
var maxHeight: Int = 0
}
//每个item的定义
class Item(val useHeight: Int, val view: View, var rect: Rect)
}
以上就是直播网站程序源码,FlowLayoutManager 流式布局, 更多内容欢迎关注之后的文章
标签:val,views,frame,流式,item,源码,FlowLayoutManager,var,row From: https://www.cnblogs.com/yunbaomengnan/p/16993719.html