Kotlin实现流式布局

本篇旨在使用kotlin代码实现TextView的流式排版,采用继承于ViewGroup的形式进行构建。

流式布局采用的方式是由左至右,由上至下的形式。简单的理解就是textview先排满一行后,再排下一行。按照此方式,我们可以确定,每一行应该由一个TextView的集合,同时也应该会确定一个统一的行高:

/**
 * 行视图集合
 */
class FlowChips {
    /**
     * 子视图
     */
     var views: MutiableList<View> = mutableListOf()

    /**
     * 行高
     */
     var rowHeight: Int = 0
}

以下开始实现FlowLayout:

class FlowLayout : ViewGroup {

    private val DEBUG: Boolean = false

    private val TAG: String = "FlowLayout"

    /**
     * 列间隔
     */
    private var mHorizontalSpacing: Int = 10

    /**
     * 行间隔
     */
    private var mVerticalSpacing: Int = 10

    private val chipArray: MutableList<FlowChips> = ArrayList<FlowChips>()

    constructor(context: Context?) : super(context)

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

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

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes)

    @SuppressLint("DrawAllocation")
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        chipArray.clear()
        val selfWidth = MeasureSpec.getSize(widthMeasureSpec)
        val selfHeight = MeasureSpec.getSize(heightMeasureSpec)
        val selfHeightMode = MeasureSpec.getMode(heightMeasureSpec)
        val selfWidthMode = MeasureSpec.getMode(widthMeasureSpec)

        var rowChips = FlowChips()
        var rowHeight: Int = 0;
        var rowWidthUsed: Int = 0;
        var totalHeight: Int = 0;
        for (i in 0 until childCount) {
            val childView = getChildAt(i)
            val lp = childView.layoutParams
            val childWidthMeasureSpec = getChildMeasureSpec(MeasureSpec.makeMeasureSpec(selfWidth, selfWidthMode), childView.paddingStart + childView.paddingEnd, lp.width)
            val childHeightMeasureSpec = getChildMeasureSpec(MeasureSpec.makeMeasureSpec(selfHeight, selfHeightMode), childView.paddingTop + childView.paddingBottom, lp.height)
            childView.measure(childWidthMeasureSpec, childHeightMeasureSpec)

            var rowHeightTemp = rowHeight.coerceAtLeast(childView.measuredHeight)
            var widthUsedTemp = rowWidthUsed
            widthUsedTemp += childView.measuredWidth
            if (widthUsedTemp > selfWidth) {
                // 超过父View宽度
                // 此行结束,换行
                totalHeight += rowHeight + mVerticalSpacing;
                chipArray.add(rowChips)

                rowChips = FlowChips()
                rowWidthUsed = childView.measuredWidth
                rowHeight = childView.measuredHeight
                rowChips.rowHeight = rowHeight;
                rowChips.views.add(childView)
            } else {
                rowWidthUsed = widthUsedTemp + mHorizontalSpacing
                rowChips.rowHeight = rowHeightTemp;
                rowChips.views.add(childView)
            }
            if (i == childCount - 1) {
                totalHeight += rowHeight + mVerticalSpacing
                rowChips.rowHeight = rowChips.rowHeight.coerceAtLeast(rowHeight)
                chipArray.add(rowChips)
            }
        }
        setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(totalHeight.coerceAtLeast(selfHeight), selfHeightMode))
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        var currentLeft = paddingStart
        var currentTop = paddingTop
        for(chips in chipArray) {
            for(view in chips.views) {
                var start = currentLeft;
                var top = currentTop;
                var end = start + view.measuredWidth
                var bottom = top + view.measuredHeight
                view.layout(start, top, end, bottom)
                currentLeft = end + mHorizontalSpacing
            }
            currentLeft = paddingStart
            currentTop += chips.rowHeight + mVerticalSpacing
        }
    }

}

完结

posted @ 2022-10-20 03:13  swalka`x  阅读(144)  评论(0编辑  收藏  举报