无论是在移动端的App,还是在前端的网页,我们经常会看到下面这种标签的列表效果:

标签从左到右摆放,一行显示不下时自动换行。这样的效果用Android源生的控件很不好实现,所以往往需要我们自己去自定义控件。我在开发中就遇到过几次要实现这样的标签列表效果,所以就自己写了个控件,放到我的GitHub,方便以后使用。有兴趣的同学也欢迎访问我的GitHub、查看源码实现和使用该控件。下面我将为大家介绍该控件的具体实现和使用。
要实现这样一个标签列表其实并不难,列表中的item可以直接用TextView来实现,我们只需要关心列表控件的大小和标签的摆放就可以了。也就是说我们需要做的只要两件事:测量布局(onMeasure)和摆放标签(onLayout)。这是自定义ViewGroup的基本步骤,相信对自定义View有所了解的同学都不会陌生。下面我们就来看看具体的代码实现。
控件的测量:

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int count = getChildCount();int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();int contentHeight = 0; //记录内容的高度int lineWidth = 0; //记录行的宽度int maxLineWidth = 0; //记录最宽的行宽int maxItemHeight = 0; //记录一行中item高度最大的高度boolean begin = true; //是否是行的开头//循环测量item并计算控件的内容宽高for (int i = 0; i < count; i++) {View view = getChildAt(i);measureChild(view, widthMeasureSpec, heightMeasureSpec);if(!begin) {lineWidth += mWordMargin;}else {begin = false;}//当前行显示不下item时换行。if (maxWidth <= lineWidth + view.getMeasuredWidth()) {contentHeight += mLineMargin;contentHeight += maxItemHeight;maxItemHeight = 0;maxLineWidth = Math.max(maxLineWidth, lineWidth);lineWidth = 0;begin = true;}maxItemHeight = Math.max(maxItemHeight, view.getMeasuredHeight());lineWidth += view.getMeasuredWidth();}contentHeight += maxItemHeight;maxLineWidth = Math.max(maxLineWidth, lineWidth);//测量控件的最终宽高setMeasuredDimension(measureWidth(widthMeasureSpec,maxLineWidth),measureHeight(heightMeasureSpec, contentHeight));}//测量控件的宽private int measureWidth(int measureSpec, int contentWidth) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);if (specMode == MeasureSpec.EXACTLY) {result = specSize;} else {result = contentWidth + getPaddingLeft() + getPaddingRight();if (specMode == MeasureSpec.AT_MOST) {result = Math.min(result, specSize);}}//这一句是为了支持minWidth属性。result = Math.max(result, getSuggestedMinimumWidth());return result;}//测量控件的高private int measureHeight(int measureSpec, int contentHeight) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);if (specMode == MeasureSpec.EXACTLY) {result = specSize;} else {result = contentHeight + getPaddingTop() + getPaddingBottom();if (specMode == MeasureSpec.AT_MOST) {result = Math.min(result, specSize);}}//这一句是为了支持minHeight属性。result = Math.max(result, getSuggestedMinimumHeight());return result;}
  • 标签的摆放:
    @Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {int x = getPaddingLeft();int y = getPaddingTop();int contentWidth = right - left;int maxItemHeight = 0;int count = getChildCount();//循环摆放itemfor (int i = 0; i < count; i++) {View view = getChildAt(i);//当前行显示不下item时换行。if (contentWidth < x + view.getMeasuredWidth() + getPaddingRight()) {x = getPaddingLeft();y += mLineMargin;y += maxItemHeight;maxItemHeight = 0;}view.layout(x, y, x + view.getMeasuredWidth(), y + view.getMeasuredHeight());x += view.getMeasuredWidth();x += mWordMargin;maxItemHeight = Math.max(maxItemHeight, view.getMeasuredHeight());}}
  • onMeasure和onLayout的实现代码基本是一样的,不同的只是一个是测量宽高,一个是摆放位置而已。实现起来非常的简单。

以上是LabelsView的核心代码,LabelsView除了实现了item的测量和摆放以外,还提供了一系列的方法让使用者可以方便设置标签的样式(包括标签被选中的样式)和标签点击、选中的监听等。下面LabelsView的使用介绍。

1、引入依赖
在Project的build.gradle在添加以下代码

allprojects {repositories {...maven { url 'https://jitpack.io' }}
}

在Module的build.gradle在添加以下代码

dependencies {compile 'com.github.donkingliang:LabelsView:1.4.1'
}

2、编写布局:

   <com.donkingliang.labels.LabelsView
       xmlns:app="http://schemas.android.com/apk/res-auto"
       android:id="@+id/labels"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:labelBackground="@drawable/label_bg"     //标签的背景
       app:labelTextColor="@drawable/label_text_color" //标签的字体颜色 可以是一个颜色值
       app:labelTextSize="14sp"      //标签的字体大小
       app:labelTextPaddingBottom="5dp"   //标签的上下左右边距
       app:labelTextPaddingLeft="10dp"
       app:labelTextPaddingRight="10dp"
       app:labelTextPaddingTop="5dp"
       app:lineMargin="10dp"   //行与行的距离
       app:wordMargin="10dp"   //标签与标签的距离
       app:selectType="SINGLE"   //标签的选择类型 有单选(可反选)、单选(不可反选)、多选、不可选四种类型
       app:maxSelect="5" />  //标签的最大选择数量,只有多选的时候才有用,0为不限数量

这里有两个地方需要说明一下:

1)标签的正常样式和选中样式是通过drawable来实现的。比如下面两个drawable。

<!-- 标签的背景 label_bg -->
<selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- 标签选中时的背景 --><item android:state_selected="true"><shape><stroke android:width="2dp" android:color="#fb435b" /><corners android:radius="8dp" /><solid android:color="@android:color/white" /></shape></item><!-- 标签的正常背景 --><item><shape><stroke android:width="2dp" android:color="#656565" /><corners android:radius="8dp" /><solid android:color="@android:color/white" /></shape></item>
</selector>
<!-- 标签的文字颜色 label_text_color -->
<selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- 标签选中时的文字颜色 --><item android:color="#fb435b" android:state_selected="true" /><!-- 标签的正常文字颜色 --><item android:color="#2d2b2b" />
</selector>

TextView的textColor属性除了可以设置一个颜色值以外,也可以通过资源来设置的,这一点很多同学都不知道。

2)标签的选择类型有四种:

NONE :标签不可选中,也不响应选中事件监听,这是默认值。

SINGLE:单选(可反选)。这种模式下,可以一个也不选。

SINGLE_IRREVOCABLY:单选(不可反选)。这种模式下,有且只有一个是选中的。默认是第一个。

MULTI:多选,可以通过设置maxSelect限定选择的最大数量,0为不限数量。maxSelect只有在多选的时候才有效。多选模式下可以设置一些标签为必选项。必选项的标签默认选中,且不能取消。

3、设置标签:

labelsView = (LabelsView) findViewById(labels);
ArrayList<String> label = new ArrayList<>();
label.add("Android");
label.add("IOS");
label.add("前端");
label.add("后台");
label.add("微信开发");
label.add("游戏开发");
labelsView.setLabels(label); //直接设置一个字符串数组就可以了。//LabelsView可以设置任何类型的数据,而不仅仅是String。
ArrayList<TestBean> testList = new ArrayList<>();
testList.add(new TestBean("Android",1));
testList.add(new TestBean("IOS",2));
testList.add(new TestBean("前端",3));
testList.add(new TestBean("后台",4));
testList.add(new TestBean("微信开发",5));
testList.add(new TestBean("游戏开发",6));
labelsView.setLabels(testList, new LabelsView.LabelTextProvider<TestBean>() {@Overridepublic CharSequence getLabelText(TextView label, int position, TestBean data) {//根据data和position返回label需要显示的数据。return data.getName();}
});

4、设置事件监听:(如果需要的话)

//标签的点击监听
labelsView.setOnLabelClickListener(new LabelsView.OnLabelClickListener() {@Overridepublic void onLabelClick(TextView label, Object data, int position) {//label是被点击的标签,data是标签所对应的数据,position是标签的位置。}
});
//标签的选中监听
labelsView.setOnLabelSelectChangeListener(new LabelsView.OnLabelSelectChangeListener() {@Overridepublic void onLabelSelectChange(TextView label, Object data, boolean isSelect, int position) {//label是被选中的标签,data是标签所对应的数据,isSelect是是否选中,position是标签的位置。}
});

5、常用方法

//设置选中标签。
//positions是个可变类型,表示被选中的标签的位置。
//比喻labelsView.setSelects(1,2,5);选中第1,3,5个标签。如果是单选的话,只有第一个参数有效。
public void setSelects(int... positions);
public void setSelects(List<Integer> positions);//获取选中的标签(返回的是所有选中的标签的位置)。返回的是一个Integer的数组,表示被选中的标签的下标。如果没有选中,数组的size等于0。
public ArrayList<Integer> getSelectLabels();
//获取选中的label(返回的是所有选中的标签的数据)。如果没有选中,数组的size等于0。T表示标签的数据类型。
public <T> List<T> getSelectLabelDatas();//取消所有选中的标签。
public void clearAllSelect();//设置标签的选择类型,有NONE、SINGLE、SINGLE_IRREVOCABLY和MULTI四种类型。
public void setSelectType(SelectType selectType);//设置最大的选择数量,只有selectType等于MULTI是有效。
public void setMaxSelect(int maxSelect);//设置必选项,只有在多项模式下,这个方法才有效
public void setCompulsorys(int... positions)
public void setCompulsorys(List<Integer> positions)//清空必选项,只有在多项模式下,这个方法才有效
public void clearCompulsorys()//设置标签背景
public void setLabelBackgroundResource(int resId);//设置标签的文字颜色
public void setLabelTextColor(int color);
public void setLabelTextColor(ColorStateList color);//设置标签的文字大小(单位是px)
public void setLabelTextSize(float size);//设置标签内边距
public void setLabelTextPadding(int left, int top, int right, int bottom);//设置行间隔
public void setLineMargin(int margin);//设置标签的间隔
public void setWordMargin(int margin);

所有的set方法都有对应的get方法,这里就不说了。

效果图:

最后给出该控件在GitHub中的地址,欢迎大家访问和使用。
https://github.com/donkingliang/LabelsView

转载自:https://blog.csdn.net/u010177022/article/details/60324117

Android自定义标签列表控件LabelsView相关推荐

  1. Android自定义标签列表控件LabelsView解析

    无论是在移动端的App,还是在前端的网页,我们经常会看到下面这种标签的列表效果: 标签从左到右摆放,一行显示不下时自动换行.这样的效果用Android源生的控件很不好实现,所以往往需要我们自己去自定义 ...

  2. labelview标签列表控件的使用介绍

    标签列表控件的使用介绍 支持点击事件监听 step1: D:\workspace\LabelViewDemoTwo\app\src\main\res\values\strings.xml <re ...

  3. Android自定义AlertDialog的控件获取操作

    Android自定义AlertDialog的控件获取操作 在自定义的AlertDialog布局虽然可以显示,但是试过很多方法都不能获得其中的控件进行操作,找了很多方法最后这种方法可以. dialog的 ...

  4. Android ExpandableListView 展开列表控件(手机QQ好友列表)

    你是否觉得手机QQ上的好友列表那个控件非常棒?  不是.....   那也没关系, 学多一点知识对自己也有益无害. 那么我们就开始吧. 展开型列表控件, 原名ExpandableListView 是普 ...

  5. android日历价格控件,Android 自定义价格日历控件

    介绍 上个星期项目有一个日历价格的需求,类似一个商品在不同的日期价格可能会不同,由于时间给得特别紧所以打算找个合适的开源项目进行修改.参考了网上大多数是通过继承view直接draw一个monthVie ...

  6. android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...

    转载:http://blog.csdn.net/xiabing082/article/details/48781489 1.  大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...

  7. Android自定义的下拉列表框控件

    一.概述 Android中的有个原生的下拉列表控件Spinner,但是这个控件有时候不符合我们自己的要求, 比如有时候我们需要类似windows 或者web网页中常见的那种下拉列表控件,类似下图这样的 ...

  8. android 镂空字体下载,Android——自定义镂空掩饰控件

    刚学完ViewDragHelper和PorterDuffXferMode的我,突然想做一个这样效果的自定义控件:点击ListView的列表项,通过ViewDragHelper用动画方式上下各弹出一个控 ...

  9. android自定义xml弹窗,Android自定义弹窗提醒控件使用详解

    Android中原生的Dialog弹窗提醒控件样式单一,有时候并不能满足我们的项目需求,而且一个工程里面有时候会在多处都用到弹窗提醒的功能,代码会出现大量的冗余,工作之余,就自己实现了这么一个弹窗提醒 ...

最新文章

  1. synchronize
  2. python学习干货教程(10):列表
  3. PHP教程-防止网站被刷票的小技巧
  4. Intent 的用法
  5. codeforces 96A-C语言解题报告
  6. mysql stdistance_postgis的geography_columns和geometry_columns有什么区别
  7. DataGridView
  8. Spring Boot + Log4j2 日志框架配置 (Maven)
  9. html文件图标变成白色,win10系统html文件图标变成空白的操作办法
  10. win7清理系统后,音频设备被禁用,没有声音
  11. [No0000151]菜鸟理解.NET Framework中的CLI,CLS,CTS,CLR,FCL,BCL
  12. 移动app设计公司流程—APP设计需求分析规范
  13. adb工具下载及配置使用
  14. 航测无人机测绘地理信息免费资料
  15. win10更改user用户名(win10更改user用户名文件夹已在另一个文件中已打开)
  16. 专访有赞 CTO 崔玉松:打造中国 SaaS 领域最好的开店软件解决方案
  17. gdb调试查看内存数据
  18. Python常用内置函数enumerate()详细用法介绍
  19. 数据模型LP32 ILP32 LP64 LLP64 ILP64
  20. Rabbitmq客户端接收消息为字符数组解决

热门文章

  1. 使用docker搭建网站
  2. tft注册最后验证图片_英雄联盟手游自走棋下载安装教程:三分钟教学注册下载云顶之弈正版手游...
  3. 吃鸡显示该服务器不可使用是啥意思,绝地求生客户机服务器版本不匹配是啥意思 | 手游网游页游攻略大全...
  4. Python字典获取值
  5. GoodSync新用户快速入门学习篇
  6. 小米持MIX3步入5G市场
  7. Vue新搭档TypeScript快速入门实践
  8. 为 macOS 10.15 开启 HiDPI,让 2K 显示器更舒适
  9. 微信小程序API——向服务器发送请求
  10. c语言先序遍历递归算法