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

评论
发表评论
       
       
取消