首页 > 编程语言 >直播网站程序源码,FlowLayoutManager 流式布局

直播网站程序源码,FlowLayoutManager 流式布局

时间:2022-12-20 10:57:08浏览次数:44  
标签:val views frame 流式 item 源码 FlowLayoutManager var row

直播网站程序源码,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

相关文章