Android标签流控件的实现
jopen
10年前
我们从服务器端获取标签的信息,然后将其动态的添加到布局中,并且我们能够得到我们选择容器的信息,并将选中的标签重新返回至服务器。
前言
在我们的开发过程中,常常会遇到这样的场景:
我们展示一种物品或者为某一事物添加一些标签。比如说,我们买一件衣服,可以有以下几种标签:杰克琼斯,男士,运动等等。
但我们这时候可能并不知道标签的数量和每个标签的文字,所以,我们在开发过程中,需要实现下面的功能:
我们从服务器端获取标签的信息,然后将其动态的添加到布局中,并且我们能够得到我们选择容器的信息,并将选中的标签重新返回至服务器。
因此,我们必须计算出每个标签(Button)的长度,并且将其与它的容器做比较,如果容器剩余的长度并不足以容纳一个标签的时候,那么就会另起一行,添加标签,就这样周而复始,直到所有的标签添加到容器中。
实现
我们将我们自定义的控件命名为TagCloudLayout,它继承ViewGroup 并将它作为标签的容器。同时覆写onMeasure()和onLayout方法
onMeasure()方法
通过覆写onMeasure()方法,我们可以计算出容器和各标签的长度和宽度,代码如下:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int wantHeight = 0; int wantWidth = resolveSize(0, widthMeasureSpec); int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); int childLeft = paddingLeft; int childTop = paddingTop; int lineHeight = 0; for (int i = 0; i < getChildCount(); i++) { final View childView = getChildAt(i); if (childView.getVisibility() == View.GONE) { continue; } LayoutParams params = childView.getLayoutParams(); childView.measure( getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, params.width), getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom, params.height) ); int childHeight = childView.getHeight(); int childWidth = childView.getWidth(); lineHeight = Math.max(childHeight, lineHeight); if (childLeft + childWidth + paddingRight > wantWidth) { childLeft = paddingLeft; childTop += mLineSpacing + childHeight; lineHeight = childHeight; } else { childLeft += childWidth + mTagSpacing; } } wantHeight = childTop + lineHeight + paddingBottom; setMeasuredDimension(wantWidth, resolveSize(wantHeight, heightMeasureSpec)); }
onLayout()方法
计算好长度和宽度之后,我们就可以进行布局了。
protected void onLayout(boolean changed, int l, int t, int r, int b) { int width = r - l; int paddingLeft = getPaddingLeft(); int paddingTop = getPaddingTop(); int paddingRight = getPaddingRight(); int childLeft = paddingLeft; int childTop = paddingTop; int lineHeight = 0; for (int i = 0, childCount = getChildCount(); i < childCount; ++i) { final View childView = getChildAt(i); if (childView.getVisibility() == View.GONE) { continue; } int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); lineHeight = Math.max(childHeight, lineHeight); if (childLeft + childWidth + paddingRight > width) { childLeft = paddingLeft; childTop += mLineSpacing + lineHeight; lineHeight = childHeight; } childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); childLeft += childWidth + mTagSpacing; } }
在主应用程序调用
这样的话,我们的控件的主要方法就完成了,接下来我们就可以在主应用程序中直接调用了,代码如下:
TagCloudLayout mContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.test_btn); mContainer = (TagCloudLayout) findViewById(R.id.container); ArrayList<String> list = new ArrayList<>(); list.add("one"); list.add("你好"); list.add("three"); list.add("four"); list.add("ninkfnsadf"); list.add("fsadfsdgdsfasd"); list.add("fasdgsdagfsdafdsfsadfsadf"); list.add("adf"); list.add("one"); list.add("fasdfadfa"); list.add("fads"); list.add("中国"); list.add("one"); list.add("柴静"); list.add("three"); list.add("four"); mContainer.addData(list); mContainer.drawLayout(); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); }
效果
最后,让我们来看看实现效果
结束语
这个自定义控件我感觉还是挺实用的,所以我会抽出时间将它整理,便于他人调用,项目的地址是标签云控件,欢迎大家指正。