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

作者 donkingliang 关注

2017.03.15 20:59* 字数 759 阅读 406评论 0喜欢 3

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

标签列表

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

    @Override
protected 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); //当前行显示不下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());
if(!begin) {
lineWidth += mWordMargin;
}else {
begin = false;
}
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;
}

标签的摆放:

    @Override
protected 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();
//循环摆放item
for (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.2.0'
}

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:单选。
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("游戏开发");
label.add("Java");
label.add("JavaScript");
label.add("C++");
label.add("PHP");
label.add("Python");
label.add("Swift");
labelsView.setLabels(label); //直接设置一个字符串数组就可以了。

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

//标签的点击监听
labelsView.setOnLabelClickListener(new LabelsView.OnLabelClickListener() {
@Override
public void onLabelClick(View label, String labelText, int position) {
//label是被点击的标签,labelText是标签的文字,position是标签的位置。
}
});
//标签的选中监听
labelsView.setOnLabelSelectChangeListener(new LabelsView.OnLabelSelectChangeListener() {
@Override
public void onLabelSelectChange(View label, String labelText, boolean isSelect, int position) {
//label是被点击的标签,labelText是标签的文字,isSelect是是否选中,position是标签的位置。
}
});

5、常用方法

//设置选中标签。
//positions是个可变类型,表示被选中的标签的位置。
//比喻labelsView.setSelects(1,2,5);选中第1,3,5个标签。如果是单选的话,只有第一个参数有效。
public void setSelects(int... positions); //获取选中的标签。返回的是一个Integer的数组,表示被选中的标签的下标。如果没有选中,数组的size等于0。
public ArrayList<Integer> getSelectLabels(); //取消所有选中的标签。
public void clearAllSelect(); //设置标签的选择类型,有NONE、SINGLE和MULTI三种类型。
public void setSelectType(SelectType selectType); //设置最大的选择数量,只有selectType等于MULTI是有效。
public void setMaxSelect(int maxSelect); //设置标签背景
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方法,这里就不说了。

效果图:

效果图.gif

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

(转载)Android自定义标签列表控件LabelsView解析的更多相关文章

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

    版权声明:本文为博主原创文章,未经博主允许不得转载. 无论是在移动端的App,还是在前端的网页,我们经常会看到下面这种标签的列表效果:   标签从左到右摆放,一行显示不下时自动换行.这样的效果用And ...

  2. android 自定义空间 组合控件中 TextView 不支持drawableLeft属性

    android 自定义空间 组合控件中 TextView 不支持drawableLeft属性.会报错Caused by: android.view.InflateException: Binary X ...

  3. Android自定义控件进阶-打造Android自定义的下拉列表框控件

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

  4. Android 自定义View修炼-如何打造Android自定义的下拉列表框控件

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

  5. Android 如何打造Android自定义的下拉列表框控件

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

  6. Android自定义View和控件之一-定制属于自己的UI

    照例,拿来主义.我的学习是基于下面的三篇blog.前两是基本的流程,第三篇里有比较细致的绘制相关的属性.第4篇介绍了如何减少布局层次来提高效率. 1. 教你搞定Android自定义View 2. 教你 ...

  7. [转]android 自定义圆形imageview控件

      android布局 首先,定义定义圆形Imageview类: import android.content.Context; import android.graphics.Bitmap; imp ...

  8. Android自定义“图片+文字”控件四种实现方法之 二--------个人最推荐的一种

    http://blog.csdn.net/yanzi1225627/article/details/8633872 第二种方法也要新建一个图片+文字的xml布局文件,然后写一个类继承自LinearLa ...

  9. Android自定义上拉控件SpringView

    Demo 先看一下SpringView的效果图: 1.拖动灰色部分可拖动下方视图,点击jump按钮可让下方视图自行滑动. 使用方法 布局文件: <com.zql.android.springvi ...

随机推荐

  1. MyProject

    [PROJECT_20190101]20371230[PROJECT_20190101]

  2. vue1 到 vue2 v-el变成ref

    vue1的写法 div class="menu-wrapper" v-el="menu-wrapper"> <ul class="menu ...

  3. spring boot的项目结构问题

    问题:spring boot项目能够正常启动,但是在浏览器访问的时候会遇到404的错误,Whitelable Error Page 404 分析及解决方案:首先Application文件要放在项目的外 ...

  4. 如何快速在命令提示符(cmd)中打开指定的文件夹路径!

    按住shift键然后 右击,如图:

  5. CDR教程-海报中的立体星星怎么画

    在海报招贴.平面设计中有时需要凸显节日气氛,绘制一些立体星星图案作为陪衬.有人说cdr软件实现不了立体星星的制作,我想说,只有想不到,没有做不到.制作立体星星可通过cdr软件中的某些工具来实现,本案例 ...

  6. 取/etc/password文件最后一个单词的最后一个字符

    三种方法都可以 [root@localhost ~]# sed -n "1,5 s#.*\(.\)#\1#p" /etc/passwd [root@localhost ~]# se ...

  7. 莫烦大大TensorFlow学习笔记(9)----可视化

      一.Matplotlib[结果可视化] #import os #os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf i ...

  8. css 垂直居中方法总结

    工作中遇到垂直居中问题,特此总结了一下几种方式与大家分享.本文讨论的垂直居中仅支持IE8+ 1.使用绝对定位垂直居中 HTML <div class="container"& ...

  9. win10 1809磁盘占用总是100%

    快过年了,提前请假回家,装几台电脑公司备用.有个电脑装完系统开机很慢,开机完成之后电脑响应也很慢,于是打开任务管理器发现磁盘中用率一直是100%,然而程序读取数据的速度并不高. 解决思路: 关闭win ...

  10. TOMCAT-IDEA远程debug方法

    在很多情况下,tomcat本地启动并不足以完全模拟线上环境,所以,有时候我们可能需要远程debug方法去调试,下面附上远程idea debug方法: IDEA中,选择 Run/Debug Config ...