流式布局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>>()
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()
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
var lineViews = mutableListOf<View>()
var usedWidth = 0
var lineHeight = 0
var childNeededParentWidth = 0
var childNeededParentHeight = 0
for (i: Int in 0 until childCount) {
children.elementAt(i).measure(
getChildMeasureSpec(
widthMeasureSpec,
paddingLeft + paddingRight,
children.elementAt(i).layoutParams.width
),
getChildMeasureSpec(
heightMeasureSpec,
paddingTop + paddingBottom,
children.elementAt(i).layoutParams.height
)
)
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)
childNeededParentWidth = max(childNeededParentWidth, usedWidth + mHorizontalSpace)
childNeededParentHeight += lineHeight + mVerticalSpace
lineViews = mutableListOf()
usedWidth = 0
lineHeight = 0
}
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
}
}
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) {
var currentLeft = paddingLeft
var currentTop = paddingTop
for (i in allLinesViews.indices) {
val lineHeight = lineHeights[i]
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
}
}
}