package com.example.myapp.ui.custom
import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup
import kotlin.math.max
class FlowLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ViewGroup(context, attrs, defStyleAttr) {
private var horizontalSpacing = 0
private var verticalSpacing = 0
init {
context.obtainStyledAttributes(attrs, R.styleable.FlowLayout).apply {
horizontalSpacing = getDimensionPixelSize(
R.styleable.FlowLayout_horizontalSpacing, 0
)
verticalSpacing = getDimensionPixelSize(
R.styleable.FlowLayout_verticalSpacing, 0
)
recycle()
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
var currentWidth = paddingLeft
var currentHeight = paddingTop
var maxLineHeight = 0
for (i in 0 until childCount) {
val child = getChildAt(i)
if (child.visibility == GONE) continue
measureChildWithMargins(
child,
widthMeasureSpec,
0,
heightMeasureSpec,
0
)
val childWidth = child.measuredWidth
val childHeight = child.measuredHeight
val lp = child.layoutParams as MarginLayoutParams
val childWidthWithMargins = childWidth + lp.leftMargin + lp.rightMargin
val childHeightWithMargins = childHeight + lp.topMargin + lp.bottomMargin
if (currentWidth + childWidthWithMargins + paddingRight > widthSize) {
// Move to next line
currentWidth = paddingLeft
currentHeight += maxLineHeight + verticalSpacing
maxLineHeight = 0
}
currentWidth += childWidthWithMargins + horizontalSpacing
maxLineHeight = max(maxLineHeight, childHeightWithMargins)
}
currentHeight += maxLineHeight + paddingBottom
val finalWidth = if (widthMode == MeasureSpec.EXACTLY) widthSize else currentWidth
val finalHeight = if (heightMode == MeasureSpec.EXACTLY) heightSize else currentHeight
setMeasuredDimension(finalWidth, finalHeight)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var currentX = paddingLeft
var currentY = paddingTop
var maxLineHeight = 0
val width = r - l
for (i in 0 until childCount) {
val child = getChildAt(i)
if (child.visibility == GONE) continue
val childWidth = child.measuredWidth
val childHeight = child.measuredHeight
val lp = child.layoutParams as MarginLayoutParams
val childWidthWithMargins = childWidth + lp.leftMargin + lp.rightMargin
if (currentX + childWidthWithMargins + paddingRight > width) {
// Move to next line
currentX = paddingLeft
currentY += maxLineHeight + verticalSpacing
maxLineHeight = 0
}
val left = currentX + lp.leftMargin
val top = currentY + lp.topMargin
val right = left + childWidth
val bottom = top + childHeight
child.layout(left, top, right, bottom)
currentX += childWidthWithMargins + horizontalSpacing
maxLineHeight = max(maxLineHeight, childHeight + lp.topMargin + lp.bottomMargin)
}
}
override fun generateDefaultLayoutParams(): LayoutParams {
return MarginLayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
)
}
override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
return MarginLayoutParams(context, attrs)
}
override fun generateLayoutParams(p: LayoutParams?): LayoutParams {
return MarginLayoutParams(p)
}
override fun checkLayoutParams(p: LayoutParams?): Boolean {
return p is MarginLayoutParams
}
}