前言
标签不用说,基本所有的app都会用到这种需求,不管是电商app商品的筛选标签,还是新闻app的搜索历史记录标签,体育app的日期和赛事赛选标签,团购app的省市区的多级标签,都会有它们的身影.这次,为大家介绍自己的一个标签控件-FlowView,看看它的展现形式是不是和日常开发中的很多地方都有碰撞。
演示效果
1.展示类型:
标题 标签 可选/不可选
单选/多选 操作按钮
自动/手动列数 指定行数/指定宽度
水平/非水平滑动 网格线
(因为展示的内容比较多,所以gif压的有点厉害 (O _ O)!!!
以上9种设置基本都可以相互组合,因此FlowView多种展现类型:
2.应用场景:
演示常用的几种:
搜索历史:标题文本可以根据传入的标题layout文件定制
筛选条件:设置多个FlowView即可
网格线:支持实线,虚线
多级菜单:每一级数据由一个FlowView组成
添加/点击动画:动画支持自定义
GitHub链接
标签控件-FlowView
特性
目前标签只支持TextView及其子类,FlowView内部的每个标签便是一个TextView,通过layout文件生成,所以标签本身定制很自由,此外还支持以下特性:
1.支持标题,全选,反选,关闭,确认五种功能标签,基本可以自由组合.
2.支持普通展示标签,热门标签 单选标签,多选标签.
3.支持填充(排满一行后自动递增行数)和网格(和GridView类似)两种排列模型.
4.支持指定行数或指定列数,指定FlowView宽度(可以大于屏幕宽度),配合HorizionScrollView可以水平滑动.
5.支持添加网格线,分实线和虚线,垂直/水平,粗细,宽度等均可调整(具体看下文).
6.支持限定行数,多余行数会舍弃(和上面的指定行数不是一个特性,指定行数不会舍弃标签).
7.支持自定义标签的添加动画和点击动画,自带随机,延迟,抖动动画.
基本上,只有文本展示的有限标签列表,不再需要RecyclerView,GrilView,ListView和Adapter配合,只需要提供标签的layout文件和一组String集合即可展示.
导入
使用
1.自定义属性
自定义属性,按类型分组介绍:
(1)标签属性,这些属性必须设置,除非只使用普通展示标签,否则请务必在xml中设置或在添加标签前调用setAttr系列方法设置,建议在xml中设置.
(2)标签常规设置属性,这些不是非必须属性,fv_select_type属性不需要设置,只要调用相关的add系列方法(下文会介绍该系列方法),FlowView便会自动设置 对应的值给select_type.
至于为什么该属性设置无意义,下文会说明.
(3)指定列数和行数,水平滑动属性
如果需要FlowView展示成类似ListView的单行布局或者GridView的网格布局,请使用以下属性
(4)网格模式属性
这些属性类似ListView和GridView中的分隔线,可以根据自己项目的需求来使用
注:fv_hLineAllCover 和 fv_VlineAllCover属性
fv_hLineAllCover 和 fv_VlineAllCover均为false时,显示效果如下图
如果使用到了标题标签,可以通过设置firstHLine和titleAllCoverVLine属性来显示或隐藏第一行的横线和竖线,到达自己想要的效果.
fv_hLineAllCover 和 fv_VlineAllCover均为true时,显示效果下图
以上的自定义属性除了部分声明之外,都可以在xml中设置,但添加标签数据的add系列方法必须在代码中调用.
(2)在代码中设置,先看add系列方法:
1-0 普通-单选-多选
没有标题标签,功能标签和热门标签,最简单的展示类型
代码示例
1-1 普通 单选 多选 指定列数
设置 useGrid = true,oneLineCount=3时的展示效果,该展示类型可以替代GirdView的网格文本的场合;
oneLineCount=1,配合网格线属性 useHLine=true,可以替代LietView单行文本的场合。
代码示例
1-2 普通 单选 多选 自动列数
设置useAutoGrid=true的展示效果,可以看到比上图的手动设置列数多了一列,该展示类型是根据宽度最大的标签来计算每行最多可填充的标签数,只需要设置该属性为true,便会展示成GridView的样式.
代码使用
1-3 普通 单选 多选 限行标签
设置 limitLines = 2时的展示效果,和下面1-9水平滑动的lineCount不是一个属性,可以看到第二行之后的标签都没有展示出来。
代码使用
1-4 普通 单选 多选 标题标签
下图的标题标签就是"水果",标题的layout文件是独立的,可以自己定制.
代码使用
1-5 普通 单选 多选 关闭标签
点击关闭按钮,FlowView就会隐藏,目前关闭标签的layout文件和标签是共用的,可以通过setButtonAttr()方法设置标签字体颜色和背景。
代码使用
1-6 多选 全选标签 前置和后置
全选标签可以位于第一行开头或者末尾独立一行,layout文件和普通标签共用,也是通过setButtonAttr()方法来设置标签字体颜色和背景.
代码使用
1-7 多选 标题,全选,反选标签
反选需要设置setUseSelect = true,该展示类型的全选,反选功能标签的layout文件是独立的;
代码使用
1-8 多选 全选,反选,确定标签
该展示类型,全选,反选,确定功能标签的layout是独立的
单行/非单行标题
设置oneLineTitle= true时,标题标签会单独占一行,否则标题标签会和普通标签在同一行。
1-9 水平模式
该展示类型,需要嵌套HorizionScrollView使用,这样FlowView即可展示为类似水平滑动的ListView和GridView效果。
普通展示类型,标签可以左右滑动,setHoriztionDivisor()方法传值越大,每行的标签数就会越多
代码使用
指定列数
设置 oneLineCount的值大于0时,列数即oneLineCount,行数自动计算得出。
指定行数
设置lineCount的值大于0时,行数即为lineCount,列数会自动计算得出。
代码使用
1-10 热门标签
下图的红色标签即热门标签,当然也可以用来表示特殊标签,它们的位置和layout是独立于普通标签和功能标签的。
代码使用
1-11 网格线
设置属性 useHLine = true 可以显示水平网格线
useVLine = true 可以显示垂直网格线
lineType目前有实线和虚线两种
下图中其他属性还可以调整网格线的展示模式。
代码使用
(3)设置点击监听器和点击动画
点击监听,设置监听器后,可以监听child view的点击事件
通过FlowView的lastSelected属性可以获取单选后的标签索引
通过FlowView的getSelecteds()方法可以获取多选后的标签索引集合
点击动画,设置监听器后,在startAnimation方法中会回调点击的child view,在这里可以设置标签的点击动画.
实现思路
1.代码构建
前文已经提到,主要是在FlowView的onLayout方法中重新设置内部childview的layout,这样才能实现标签的填充模式。
首先,在addView()调用之后,FlowView的onMeature()方法会被调用,此时我们在这个方法里面计算所有child view 的文本所占用的宽度,核心的代码如下
去除FlowView的每个child,先调用child view的measure(0,0)之后,就可以通过它们的getMeasureHeight/Width()方法拿到child view占用的高度和宽度了,
接着,我们通过每行的最大宽度,逐个减去child view 的宽度(包括间隔,间距),当每行的剩余宽度不足时,前面累计的child view就添加到一个集合中,表示该行的child view集合,由此每一行能填充多少个child view就可以计算出来,
由此,可以得到一共需要多少行才能填充完所有的child view,同时上面的计算也会把FlowView所需要的高度和宽度计算出来,调用FlowView以下的方法
来调整FlowView的高度和宽度。
最后,在FlowView的onLayout()方法里,我们需要重新计算每个child view 相对于FlowView的left top right bottom 坐标,这个就是数学计算问题了,没什么难的,在调用child view的 layout()方法前,还需要注意再调用child view的measure()方法一次,这样child view的文本才会居中.
2.特性归纳
实际上,这个FlowView和上次的TipTextView是一样的,最初只是为了满足一些简单的需求,比如角标,标签,但是,我们可以发现,不管是开发中的产品设计,还是我们经常使用的app中,会发现这些类似的需求总是会有微小差别,这时,就需要我们逐步扩展自己的自定义View,只要逐步积累,控件才可以适用更多情况,而不是每次碰到一个类似的需要,把前面的东西改完后就扔一边去了,这样前面的构思岂不是又浪费了,时间久而久之,就会忘了。
虽然FlowView看上去能应付不少情况,除了gif展示的外,比如实际项目中以下几种:
但是下面这些就很尴尬了,当然这也是以后需要考虑加入的展示模式:
带图片的场景
带动画的角标场景
注意事项
第一:在使用代码的示例中,可以发现setArr系列方法需要放置在最前面,add系列方法需要放置在中间, 剩下的指定行数列数,是否可选,是否单行,是否使用网格线放置在最后; 第二点 就是,由于需要获取子View的宽高,而view的onMeasure方法是在activity的onResum()方法之后执行的,所以必须在onResum()方法之后或者监听回调的方法内添加标签到FlowView中.
这次文章比较长,因为这种需求的控件细节特别多,故而很多情况都给加进去了,如果需要具体Demo可以到我的Github获取,最后,如果喜欢觉得有帮助,给个start或赞吧.