欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Kotlin:FlowLayout横向流式自定义布局

程序员文章站 2022-09-05 11:20:12
package com.chenxh.flowlayoutimport android.content.Contextimport android.content.res.Resourcesimport android.graphics.Canvasimport android.icu.util.Measureimport android.util.AttributeSetimport android.util.Logimport android.util.TypedValueimport...

Kotlin:FlowLayout横向流式自定义布局

package com.chenxh.flowlayout

import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.icu.util.Measure
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.View
import android.view.View.MeasureSpec.EXACTLY
import android.view.ViewGroup

/**
 * @description:
 *
 * @Date: 2021/1/13
 */

class FlowLayout1 : ViewGroup {

    /**
     * 每行的View集合
     */
    private var mLinesView: MutableList<MutableList<View>> = mutableListOf()

    /**
     * 行高
     */
    private var mLineHeight: MutableList<Int> = mutableListOf()

    /**
     * 水平、垂直间距
     */
    private val mHorizontalSpacing = dp2px(20) //每个item横向间距
    private val mVerticalSpacing = dp2px(8) //每个item横向间距


    constructor(context: Context) : super(context) {

    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {

    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
    }

    fun clearData() {
        mLinesView.clear()
        mLineHeight.clear()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        clearData()

        //孩子个数
        val childCount = childCount
        ll("childCount = $childCount")

        //解析 MeasureSpec
        val selfWidth = MeasureSpec.getSize(widthMeasureSpec)
        val selfWidthMode = MeasureSpec.getMode(widthMeasureSpec)
        val selfHeight = MeasureSpec.getSize(widthMeasureSpec)
        val selfHeightMode = MeasureSpec.getMode(widthMeasureSpec)

        //当前行 使用宽度
        var lineUseWidth = 0
        //一行记录
        var lineViews = mutableListOf<View>()
        //行高
        var lineHeight = 0

        //该View 所需宽度 高度
        var parentNeedHeight = 0
        var parentNeedWidth = 0

        //遍历子View
        for (i in 0 until childCount) {

            val childView = getChildAt(i)

            val childLP = childView.layoutParams

            val childWidthMeasureSpec = getChildMeasureSpec(
                widthMeasureSpec,
                paddingLeft + paddingRight,
                childLP.width)

            val childHeightMeasureSpec = getChildMeasureSpec(
                heightMeasureSpec,
                paddingTop + paddingBottom,
                childLP.height
            )
            childView.measure(childWidthMeasureSpec, childHeightMeasureSpec)

            //子View 宽高
            val childMeasureWidth = childView.measuredWidth
            val childMeasureHeight = childView.measuredHeight
            ll("onMeasure childMeasureWidth = $childMeasureWidth")
            ll("onMeasure childMeasureHeight = $childMeasureHeight")

            if (childMeasureWidth + mHorizontalSpacing + lineUseWidth > selfWidth) {

                mLinesView.add(lineViews)
                mLineHeight.add(lineHeight)

                //存入
                parentNeedHeight += lineHeight + mVerticalSpacing
                parentNeedWidth = Integer.max(parentNeedWidth, lineUseWidth + mHorizontalSpacing)

                //重置换行
                lineViews = ArrayList()
                lineHeight = 0
                lineUseWidth = 0

            }
            
            lineViews.add(childView)
            lineUseWidth += childMeasureWidth + mHorizontalSpacing
            lineHeight = Integer.max(lineHeight, childMeasureHeight)


            if (i == childCount - 1) {
                mLinesView.add(lineViews)
                mLineHeight.add(lineHeight)
                parentNeedHeight += lineHeight + mVerticalSpacing
                parentNeedWidth = Integer.max(parentNeedWidth, lineUseWidth + mHorizontalSpacing)
            }

        }

        val realWidth = if (selfWidthMode == EXACTLY) selfWidth else parentNeedWidth
        val realHeight = if (selfHeightMode == EXACTLY) selfHeight else parentNeedHeight

        setMeasuredDimension(realWidth, realHeight)

    }


    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {

        var curL: Int = paddingLeft
        var curT: Int = paddingTop

        for (i in 0 until mLinesView.size) {
            ll("onLayout line = $i")
            val curList: MutableList<View> = mLinesView[i]
            val lineHeight: Int = mLineHeight[i]

            curList.forEach {
                val left = curL
                val top = curT
                val right = left + it.measuredWidth
                val bottom = top + it.measuredHeight

                it.layout(left, top, right, bottom)

                curL = right + mHorizontalSpacing
            }
            curL = paddingLeft
            curT += lineHeight + mVerticalSpacing

        }


    }


    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
    }


    fun dp2px(dp: Int): Int {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dp.toFloat(),
            Resources.getSystem().displayMetrics
        ).toInt()
    }

    fun ll(msg: String) {
        Log.e("chenxh1", msg)
    }

}

本文地址:https://blog.csdn.net/Mr_ChenXu/article/details/112557919