Kotlin : 自定义View--FlowLayout

先放代码,注释写的还是比较清楚的,后续再做补充

/**
 *   Created by Vola on 2020/7/5.
 */
class FlowLayout : ViewGroup {

    private var TAG = "FlowLayout"

    //  每个item横向间距
    private val mHorizontalSpacing: Int = dp2px(16)

    //  每个item纵向间距
    private val mVerticalSpacing: Int = dp2px(8)

    // 记录所有的行,一行一行的存储,用于layout
    private var allLines: MutableList<MutableList<View>> = ArrayList()
    // 记录每一行的行高,用于layout
    private var lineHeights: MutableList<Int> = ArrayList()

    constructor(context: Context) : super(context){}
    
    constructor(context: Context,attrs:AttributeSet)
     : super(context, attrs){}

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


    private fun clearMeasureParams(){
        allLines.clear()
        lineHeights.clear()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //  防止内存抖动
        clearMeasureParams()

        //  child
        var mChildCount: Int = childCount
        var mPaddingLeft: Int = paddingLeft

        var selfWidth: Int = MeasureSpec.getSize(widthMeasureSpec)
        var selfHeight: Int = MeasureSpec.getSize(heightMeasureSpec)

        //  本行已经用了多宽的size
        var lineWidthUsed: Int = 0
        //  本行的高度
        var lineHeight: Int = 0

        var lineViews: MutableList<View> = ArrayList()

        //  子View要求ViewGroup的高度
        var parentNeedHeight: Int = 0
        //  子View要求ViewGroup的宽度
        var parentNeedWidth: Int = 0


        for (i in 0 until childCount) {

            var childView: View = getChildAt(i)
            var childLP = childView.layoutParams

            if (childView.visibility != View.GONE) {
                //将layoutParams转变成为 measureSpec
                var childWidthMeasureSpec = getChildMeasureSpec(
                    widthMeasureSpec,
                    paddingLeft + paddingRight,
                    childLP.width)

                var childHeightMeasureSpec = getChildMeasureSpec(
                    heightMeasureSpec,
                    paddingTop + paddingBottom,
                    childLP.height
                )
                childView.measure(childWidthMeasureSpec, childHeightMeasureSpec)

                //  获取子View测量的宽高
                var childMeasureWidth: Int = childView.measuredWidth
                var childMeasureHeight: Int = childView.measuredHeight

                //  todo : 是否需要换行
                if (childMeasureWidth + mHorizontalSpacing + lineWidthUsed > selfWidth) {

                    allLines.add(lineViews)
                    lineHeights.add(lineHeight)

                    //  把本行的数据输入
                    parentNeedHeight += lineHeight + mVerticalSpacing
                    parentNeedWidth = max(parentNeedWidth, lineWidthUsed + mHorizontalSpacing)

                    //  本行数据重置
                    lineViews = ArrayList()
                    lineHeight = 0
                    lineWidthUsed = 0

                }
                //  TODO : 不需要换行
                lineViews.add(childView)
                lineWidthUsed += childMeasureWidth + mHorizontalSpacing
                lineHeight = max(lineHeight, childMeasureHeight)

                //  处理最后一行的数据
                if (i == mChildCount - 1) {
                    allLines.add(lineViews)
                    lineHeights.add(lineHeight)
                    parentNeedHeight += lineHeight + mVerticalSpacing
                    parentNeedWidth = max(parentNeedWidth, lineWidthUsed + mHorizontalSpacing)
                }
            }
        }

        var widthMode: Int = MeasureSpec.getMode(widthMeasureSpec)
        var heightMode: Int = MeasureSpec.getMode(heightMeasureSpec)

        var realWidth:Int =if(widthMode==MeasureSpec.EXACTLY) selfWidth else parentNeedWidth

        var realHeight:Int = if(heightMode==MeasureSpec.EXACTLY) selfHeight else parentNeedHeight

        setMeasuredDimension(realWidth, realHeight)

    }



    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {

        var curL: Int = paddingLeft
        var curT: Int = paddingTop

        for (i in 0 until allLines.size) {

            var curList: MutableList<View> = allLines[i]
            var lineHeight: Int = lineHeights[i]

            for (j in 0 until curList.size) {
                var curView: View = curList[j]
                var left = curL
                var top = curT
                var right = left + curView.measuredWidth
                var bottom =top+curView.measuredHeight

                curView.layout(left, top, right, bottom)
                curL = right + mHorizontalSpacing

            }
            curL = paddingLeft
            curT += lineHeight + mVerticalSpacing

        }

    }

    private fun dp2px(dp: Int): Int {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dp.toFloat(),
            Resources.getSystem().displayMetrics
        ).toInt()
    }

}

----->Github地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值