文档章节

标签流控件的实现

fyales
 fyales
发布于 2015/03/04 20:46
字数 810
阅读 651
收藏 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

没有更多内容

加载失败,请刷新页面

加载更多

Mariadb二进制包安装,Apache安装

安装mariadb 下载二进制包并解压 [root@test-a src]# wget https://downloads.mariadb.com/MariaDB/mariadb-10.2.6/bintar-linux-glibc_214-x86_64/mariadb-10.2.6-linux-glibc_214-x86_64.t......

野雪球
今天
3
0
ConcurrentHashMap 高并发性的实现机制

ConcurrentHashMap 的结构分析 为了更好的理解 ConcurrentHashMap 高并发的具体实现,让我们先探索它的结构模型。 ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEnt...

TonyStarkSir
今天
3
0
大数据教程(7.4)HDFS的java客户端API(流处理方式)

博主上一篇博客分享了namenode和datanode的工作原理,本章节将继前面的HDFS的java客户端简单API后深度讲述HDFS流处理API。 场景:博主前面的文章介绍过HDFS上存的大文件会成不同的块存储在不...

em_aaron
昨天
4
0
聊聊storm的window trigger

序 本文主要研究一下storm的window trigger WindowTridentProcessor.prepare storm-core-1.2.2-sources.jar!/org/apache/storm/trident/windowing/WindowTridentProcessor.java public v......

go4it
昨天
7
0
CentOS 生产环境配置

初始配置 对于一般配置来说,不需要安装 epel-release 仓库,本文主要在于希望跟随 RHEL 的配置流程,紧跟红帽公司对于服务器的配置说明。 # yum update 安装 centos-release-scl # yum ins...

clin003
昨天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部