文档章节

标签流控件的实现

fyales
 fyales
发布于 2015/03/04 20:46
字数 810
阅读 650
收藏 7

前言

原文地址 在我们的开发过程中,常常会遇到这样的场景:

我们展示一种物品或者为某一事物添加一些标签。比如说,我们买一件衣服,可以有以下几种标签:杰克琼斯,男士,运动等等。

但我们这时候可能并不知道标签的数量和每个标签的文字,所以,我们在开发过程中,需要实现下面的功能:

我们从服务器端获取标签的信息,然后将其动态的添加到布局中,并且我们能够得到我们选择容器的信息,并将选中的标签重新返回至服务器。

因此,我们必须计算出每个标签(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) {
        }
    });

}

效果

最后,让我们来看看实现效果 <br /> <br /> pic <br /> <br />

结束语

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

参考资料

Johnny Huang的博客

© 著作权归作者所有

共有 人打赏支持
fyales
粉丝 1
博文 18
码字总数 21081
作品 0
浦东
程序员
Android中常见的热门标签的流式布局的实现

一、概述: 在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出) ...

拉偶有所依
2015/04/14
0
4
歌词显示控件的实现上——歌词解析

最近打算仿网易云音乐的音乐播放器,除了网络框架、接口数据等这些外,最核心的就是音乐的播放和歌词的显示。 考虑到歌词显示控件涉及到歌词解析,自定义控件的实现等等诸多方面,可能文章的...

安卓干货营
2017/10/31
0
0
AutoFlowLayout:多功能流式布局与网格布局控件

近期工作需要用到流式布局,网上也有很多关于这方面的资料。发现流式布局与网格布局的自定义很有意思,是学习自定义控件的一个很好的方式,所以就撸了个几百行代码的控件,既实用又具有学习价...

2017/08/07
0
0
【Android】商品详情页实现

我告诉自己,要独立,要坚强,要勇敢,要活的漂亮,要让自己永远善良。 现今的市场说O2O模式很火一点都不假,例如电商,各行各业都在做电商。而做电商平台必不可少的是商品详情页,那么如何实...

zrunker
2017/10/25
0
0
webTRC实现视频会议的问题

各位大佬们,本人在基于webRTC + websocke实现视频聊天会议室遇到一个问题,就是实现本地视频的回调显示,在一对一或者多人视频的时候,只要有两人或两人以上者开启视频,就会出现websocke断...

ProMonkeys
07/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

正弦 余弦 角度 用于画时钟

<html> <head> <title>时钟</title> </head> <style> #canvas{ background: #1977ca } </style>......

一箭落旄头
24分钟前
1
0
drupal7自定义模块之表单(新手向)

前段时间要给网站做个高级搜索的功能,但drupal7自带的搜索远远无法满足需求,便有了自己开发的需求 我以前没有接触过drupal,做这个功能也是困难重重,几乎是从零开始,我将目光放到了自定义模块...

gcudwork
29分钟前
0
0
驰狼课堂

http://www.chilangedu.com/

求是科技
46分钟前
0
0
jumpserver 报错"Incorrect string value

申明 本文所有内容参考自jumpserver记录命令无法入库问题 #1773 简介 jumpserver 1.4.0在jumpserver.log中大量报错,错误日志 File "/opt/jumpserver/apps/terminal/api.py", line 246, i...

zhnxin
53分钟前
2
0
用户管理相关配置文件及命令

9月19日任务 2.27linux和windows互传文件 3.1 用户配置文件和密码配置文件 3.2 用户组管理 3.3 用户管理 扩展知识 实用小工具 简单命令行下实现Linux/Windows文件互传 前提:使用远程工具Xsh...

robertt15
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部