Kotlin版本的FlowLayout
2021-08-06/2021-08-06
效果如上,直接上代码
暂时未考虑一行文字过长导致一行装不下的问题,考虑了margin
package com.example.customeview.CustomLayout
import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.view.ViewGroup
import androidx.core.view.children
import kotlin.math.max
class FlowLayout(context: Context?, attrs: AttributeSet?) : ViewGroup(context, attrs) {
private val childrenBounds = mutableListOf<Rect>()
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val sizeWidth = MeasureSpec.getSize(widthMeasureSpec)
val sizeHeight = MeasureSpec.getSize(heightMeasureSpec)
val modeWidth = MeasureSpec.getMode(widthMeasureSpec)
val modeHeight = MeasureSpec.getMode(heightMeasureSpec)
var maxLineWidth = 0
var maxLineHeight = 0
var currentLineWidth = 0
var currentLineHeight = 0
for ((index, child) in children.withIndex()) {
measureChild(child, widthMeasureSpec, heightMeasureSpec)
//考虑到onMeasure可能调用多次,因此加个if判断语句
if(childrenBounds.size<index+1) childrenBounds.add(Rect())
val layoutParams = child.layoutParams as MarginLayoutParams
val measuredWidth = child.measuredWidth
val measuredHeight = child.measuredHeight
//暂时未考虑一行文字过长导致一行装不下的问题
if(currentLineWidth+layoutParams.leftMargin+layoutParams.rightMargin+child.measuredWidth>sizeWidth){
currentLineWidth=0
childrenBounds[index].left=currentLineWidth+layoutParams.leftMargin
childrenBounds[index].right=currentLineWidth+measuredWidth+layoutParams.leftMargin
currentLineWidth=layoutParams.leftMargin+layoutParams.rightMargin+child.measuredWidth
maxLineWidth= max(maxLineWidth,currentLineWidth)
currentLineHeight+=maxLineHeight
maxLineHeight=0
childrenBounds[index].top=currentLineHeight+layoutParams.topMargin
childrenBounds[index].bottom=currentLineHeight+layoutParams.topMargin+measuredHeight
maxLineHeight=max(maxLineHeight,layoutParams.bottomMargin+layoutParams.topMargin+measuredHeight)
}else{
childrenBounds[index].left=currentLineWidth+layoutParams.leftMargin
childrenBounds[index].right=currentLineWidth+measuredWidth+layoutParams.leftMargin
currentLineWidth+=layoutParams.leftMargin+layoutParams.rightMargin+child.measuredWidth
maxLineWidth= max(maxLineWidth,currentLineWidth)
childrenBounds[index].top=currentLineHeight+layoutParams.topMargin
childrenBounds[index].bottom=currentLineHeight+layoutParams.topMargin+measuredHeight
maxLineHeight=max(maxLineHeight,layoutParams.bottomMargin+layoutParams.topMargin+measuredHeight)
}
}
val height = if (modeHeight == MeasureSpec.EXACTLY) sizeHeight else maxLineHeight
val width = if (modeWidth == MeasureSpec.EXACTLY) sizeWidth else maxLineWidth
setMeasuredDimension(width, height)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
for ((index, child) in children.withIndex()) {
child.layout(childrenBounds[index].left, childrenBounds[index].top, childrenBounds[index].right, childrenBounds[index].bottom)
}
}
override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
return MarginLayoutParams(context, attrs)
}
}
xml 文件
<?xml version="1.0" encoding="utf-8"?>
<com.example.customeview.CustomLayout.FlowLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.customeview.CustomLayout.ColoredTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="北京市" />
<com.example.customeview.CustomLayout.ColoredTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="天津市" />
<com.example.customeview.CustomLayout.ColoredTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上海市" />
<com.example.customeview.CustomLayout.ColoredTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="重庆市" />
<com.example.customeview.CustomLayout.ColoredTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:text="衡阳市" />
</com.example.customeview.CustomLayout.FlowLayout>
ColoredTextView
package com.example.customeview.CustomLayout
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import com.example.customeview.dp
import java.util.*
private val COLORS = intArrayOf(
Color.parseColor("#E91E63"),
Color.parseColor("#673AB7"),
Color.parseColor("#3F51B5"),
Color.parseColor("#2196F3"),
Color.parseColor("#009688"),
Color.parseColor("#FF9800"),
Color.parseColor("#FF5722"),
Color.parseColor("#795548")
)
private val TEXT_SIZES = intArrayOf(16, 22, 28)
private val CORNER_RADIUS = 4.dp
private val X_PADDING = 16.dp.toInt()
private val Y_PADDING = 8.dp.toInt()
class ColoredTextView(context: Context, attrs: AttributeSet?) : AppCompatTextView(context, attrs) {
private var paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val random = Random()
init {
setTextColor(Color.WHITE)
textSize = TEXT_SIZES[random.nextInt(3)].toFloat()
paint.color = COLORS[random.nextInt(COLORS.size)]
setPadding(X_PADDING, Y_PADDING, X_PADDING, Y_PADDING)
}
override fun onDraw(canvas: Canvas) {
canvas.drawRoundRect(0f, 0f, width.toFloat(), height.toFloat(), CORNER_RADIUS, CORNER_RADIUS, paint)
super.onDraw(canvas)
}
}
标题:Kotlin版本的FlowLayout
作者:OkAndGreat
地址:http://zhongtai521.wang/articles/2021/08/06/1628246661917.html