Android自定义瀑布流文字展示

在历史搜索功能中,我们常用到一个瀑布流展示控件,用来展示我们的搜索记录,所以就自定义一个吧!
布局中代码示例

  <com.example.mymodularization.measure.LinearCustom
            android:id="@+id/ll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

我们的宽和高都是wrap_content,那么我们就应该首选对自定义的控件的meause进行测量

  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var height = 0
        var width = 0
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        // 测量我们的子view
        measureChildren(widthMeasureSpec, heightMeasureSpec)
        when (widthMode) {
         // 我们的宽和高是根据我们的填充的数据来测量最后得到的,既然是wrap_content,那么我们的测量模式就是AT_MOST。
            MeasureSpec.AT_MOST -> {
            // 我们遍历子view,根据判断子view的宽度是否大于当前屏幕的宽度,得到我们最终的高度
                for (i in 0 until childCount) {
                    val view = getChildAt(i)
                    width += view.measuredWidth
                    // 如果大于屏幕宽度,加上下一行的view高度
                    if (width > widthPixels) {
                        height += view.measuredHeight
                    }
                    // 提前对下一个view宽度测量,超过加上下一行高度
                    if (i + 1 < childCount) {
                        if (view.measuredWidth + width > widthPixels) {
                            height += view.measuredHeight
                        }
                    }
                }
            }
        }
        // 最终的测量就根据我们的屏幕宽度和测量到的高度
        setMeasuredDimension(widthPixels, height)
    }

既然测量好了,那么就要对我们view进行布局

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        var left = 10
        var top = 10
        for (i in 0 until childCount) {
            getChildAt(i).layout(
                left, top, getChildAt(i).measuredWidth + left, getChildAt(i).measuredHeight + top
            )
            // 决定子view的左边缘距离
            left += getChildAt(i).measuredWidth + 10
            //  达到换行时,我们需要重新对左边距离和顶端距离进行初始化
            if (left > widthPixels) {
                left = 10
                top += getChildAt(i).measuredHeight + 10
            }
            //  预防加上下一个view的宽度超过屏幕,提前对换行做处理
            if (i + 1 < childCount) {
                if (getChildAt(i + 1).measuredWidth + left > widthPixels) {
                    left = 10
                    top += getChildAt(i).measuredHeight + 10
                }
            }
        }
    }

添加数据

// 对外提供的添加数据的方法
 fun addData(list: MutableList<String>) {
        list.forEach { s ->
            val layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
            val appCompatTextView = AppCompatTextView(context)
            appCompatTextView.text = s
            appCompatTextView.setTextColor(Color.RED)
            appCompatTextView.setBackgroundDrawable(
                context.resources.getDrawable(R.drawable.text_bg, null)
            )
            appCompatTextView.layoutParams = layoutParams
            appCompatTextView.setOnClickListener {
                Toast.makeText(context, "$s", Toast.LENGTH_SHORT).show()
            }
            // 内部调用了requsetLayout,会执行onmeause,onlayout
            addView(appCompatTextView)
        }

    }


最终效果
在这里插入图片描述
思路就是,首选我们需要确定当前自定义的view的宽和高,确定宽和高后。我们就需要确定子view的位置,位置的处理需要注意换行,当满足一行或者在下一个view的内容超过屏幕,换行的处理。
以上demo仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值