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) {          }      });    }

效果

最后,让我们来看看实现效果

Android标签流控件的实现

结束语

这个自定义控件我感觉还是挺实用的,所以我会抽出时间将它整理,便于他人调用,项目的地址是标签云控件,欢迎大家指正。

参考资料

Johnny Huang的博客

来自:http://www.fyales.com/archives/71