在历史搜索功能中,我们常用到一个瀑布流展示控件,用来展示我们的搜索记录,所以就自定义一个吧!
布局中代码示例
<com.example.mymodularization.measure.LinearCustomandroid: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 = 0var width = 0val widthMode = MeasureSpec.getMode(widthMeasureSpec)// 测量我们的子viewmeasureChildren(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 = 10var top = 10for (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 = 10top += getChildAt(i).measuredHeight + 10}// 预防加上下一个view的宽度超过屏幕,提前对换行做处理if (i + 1 < childCount) {if (getChildAt(i + 1).measuredWidth + left > widthPixels) {left = 10top += 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 = sappCompatTextView.setTextColor(Color.RED)appCompatTextView.setBackgroundDrawable(context.resources.getDrawable(R.drawable.text_bg, null))appCompatTextView.layoutParams = layoutParamsappCompatTextView.setOnClickListener {Toast.makeText(context, "$s", Toast.LENGTH_SHORT).show()}// 内部调用了requsetLayout,会执行onmeause,onlayoutaddView(appCompatTextView)}}
最终效果
思路就是,首选我们需要确定当前自定义的view的宽和高,确定宽和高后。我们就需要确定子view的位置,位置的处理需要注意换行,当满足一行或者在下一个view的内容超过屏幕,换行的处理。
以上demo仅供参考