当前位置:主页 > 查看内容

kolint版本流式布局FlowLayout

发布时间:2021-07-06 00:00| 位朋友查看

简介:流式布局FlawLayout自定义view package com . example . lsn_compose . view import android . annotation . SuppressLint import android . content . Context import android . util . AttributeSet import android . view . View import android . view .……

流式布局FlawLayout自定义view

package com.example.lsn_compose.view

import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import androidx.core.view.children
import com.blankj.utilcode.util.ConvertUtils.dp2px
import kotlin.math.max

class FlowLayout(context: Context) : ViewGroup(context) {
    private val mHorizontalSpace = dp2px(16.0F)
    private val mVerticalSpace = dp2px(8.0F)

    private var allLinesViews = mutableListOf<List<View>>()//记录所有的行,用于layout
    private var lineHeights = mutableListOf<Int>()

    constructor(context: Context, attributes: AttributeSet) : this(context)

    constructor(context: Context, attributes: AttributeSet, defStyleAttr: Int) : this(context)

    private fun clearMeasureParams() {
        allLinesViews.clear()
        lineHeights.clear()
    }

    @SuppressLint("DrawAllocation")
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        clearMeasureParams()//防止频繁创建空间而发生OOM
        //本View的宽高
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)

        var lineViews = mutableListOf<View>()//记录一行中已经添加了的View
        var usedWidth = 0//记录已经用了的宽度
        var lineHeight = 0//记录已经用了的行高

        var childNeededParentWidth = 0//所有子view加起来需要父控件给的宽度
        var childNeededParentHeight = 0//所有子view加起来父控件需要给的高度

        //先度量所有子view的宽高--->view是树形结构,递归度量
        for (i: Int in 0 until childCount) {
            //度量子view的宽高
            children.elementAt(i).measure(
                getChildMeasureSpec(
                    widthMeasureSpec,
                    paddingLeft + paddingRight,
                    children.elementAt(i).layoutParams.width
                ),
                getChildMeasureSpec(
                    heightMeasureSpec,
                    paddingTop + paddingBottom,
                    children.elementAt(i).layoutParams.height
                )
            )
            //获取子view的宽高
            val childMeasuredWidth: Int = children.elementAt(i).measuredWidth
            val childMeasuredHeight: Int = children.elementAt(i).measuredHeight

            //换行
            if (usedWidth + childMeasuredWidth + mHorizontalSpace >= width) {
                allLinesViews.add(lineViews)
                lineHeights.add(lineHeight)

                //宽度取需要父控件给的宽度和已经使用的宽度的最大值--->通常情况下,如果没到边界,子view所需要父控件所给与的宽度就是子view已经使用的宽度
                childNeededParentWidth = max(childNeededParentWidth, usedWidth + mHorizontalSpace)
                //高度就是一直累加
                childNeededParentHeight += lineHeight + mVerticalSpace
                lineViews = mutableListOf()//是否能用clear?
                usedWidth = 0
                lineHeight = 0
            }
            //流式布局是分行布置的,所以要先把每个已经算好的子view添加到每一行中,然后再把每一行添加到所有行中--->两个list
            lineViews.add(children.elementAt(i))
            //每行的宽高
            usedWidth += childMeasuredWidth + mHorizontalSpace
            lineHeight = max(lineHeight, childMeasuredHeight)

            //处理最后一行
            if (i == childCount - 1) {
                allLinesViews.add(lineViews)
                lineHeights.add(lineHeight)
                childNeededParentWidth = max(childNeededParentWidth, usedWidth + mHorizontalSpace)
                childNeededParentHeight += lineHeight + mVerticalSpace
            }
        }
        //再度量自身的viewGroup宽高---->作为一个vp,他自己也是一个view,它的大小也需要根据父view的大小来一起度量才能决定
        val widthViewMode: Int = MeasureSpec.getMode(widthMeasureSpec)
        val heightViewMode: Int = MeasureSpec.getMode(heightMeasureSpec)
        val realWidth = if (widthViewMode == MeasureSpec.EXACTLY) width else childNeededParentWidth
        val realHeight =
            if (heightViewMode == MeasureSpec.EXACTLY) height else childNeededParentHeight
        //度量自己
        setMeasuredDimension(realWidth, realHeight)
    }

    override fun onLayout(p0: Boolean, p1: Int, p2: Int, p3: Int, p4: Int) {
        //1.先获得此view的左上坐标
        var currentLeft = paddingLeft
        var currentTop = paddingTop
//        val allLineCount = allLinesViews.size
        //2.取出每一行都进行位置计算
        for (i in allLinesViews.indices) {
            val lineHeight = lineHeights[i]
            //3.取出每一行的每个element进行位置计算
            val lineView = allLinesViews[i]
            for (j in lineView.indices) {
                val view = lineView[j]
                val left = currentLeft
                val top = currentTop
                val right = left + view.measuredWidth
                val bottom = top + view.measuredHeight
                view.layout(left, top, right, bottom)
                //移动坐标,准备行内下一个元素的放置
                currentLeft = right + mHorizontalSpace
            }
            currentTop += lineHeight + mVerticalSpace
            //一行放置完毕,需要重置左边坐标
            currentLeft = paddingLeft
        }
    }
}
;原文链接:https://blog.csdn.net/wiseyue/article/details/115692868
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:如何解决 Shell 脚本重复执行的问题 下一篇:没有了

推荐图文


随机推荐