目录
1.前言
最近的版本呢,产品更新了一个直播间的需求,原本直播间的公屏聊天内容基本只展示粉丝等级、会员等级等一两个基本的标签,新的版本呢又加入了很多勋章类型的标签,需要一起展示出来(搞不懂为啥整这么多)! 区别大概就如下图所示(这些等级标签及勋章看着是不是很眼熟):
简单整理了下,大致的区别就是:
- 旧版的设计只有固定的一两个标签,然后跟上用户发送的文字等信息;
- 新版的设计要求带不固定数量的标签,少的话可能一两个,多的话标签可能还需要换行,然后跟上用户发送的文字等信息;
那么从旧版到新版需要经历哪些修改呢,一起来复习下自定义View的过程吧。
注: 为了简化处理,所有的标签自定义View都使用图片(ImageView)代替了。
2.旧版设计的分析
先来看下旧版是怎么处理的,旧版UI的蓝图如下:
可以看到,蓝图中标签视图(ImageView)和文本视图(TextView)是重叠在一起的,然而事实也是这样,在旧版的处理中,设置数据后需要手动测量所有标签视图的宽度,测量完毕后让文本缩进所有标签宽度的长度即可。
那么如何做到文本缩进的效果呢?对滴,通过对SpannableString设置相应的Span即可,它支持设置很多类型,常用的如下所示(未列举完全):
- ForegroundColorSpan
设置文字颜色
- BackgroudColorSpan
设置文字背景颜色
- ClickableSpan
设置点击效果
- URLSpan
设置超链接效果,点击跳转浏览器
- StrikethroughSpan
设置文字删除线效果
- UnderlineSpan
设置文字下划线效果
- ImageSpan
设置文字中插入图片的效果
- LeadingMarginSpan
设置文字缩进效果
添加文本缩进功能的伪代码则如下所示:
val marginWidth = 1000 // 设置缩进的长度(也就是所有标签测量出来的长度)
val marginSpan = LeadingMarginSpan.Standard(marginWidth, 0)
val spannableString = SpannableString("小青龙")
spannableString.setSpan(marginSpan, 0, 0, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.text = spannableString
3.新版设计的分析
再来看下新版的UI蓝图,根据需求,多个勋章要顺序摆放下来,如果过长还要换行处理,如下所示。相比旧版固定的一两个标签来说,增加了一丢丢难度。
这个时候旧版的功能完全无法满足我们现在的需求了,现在的标签数量不固定,可能没有,可能多到换行,所以我们只能通过自定义布局去搞定了。
具体要怎么做呢,再仔细琢磨下,标签类的控件其实都是流式布局,所有标签按照流式布局顺序摆放即可,需要换行则处理换行,但是最后一个TextView就比较特殊了,如果也按照流式布局处理的话,如下蓝图所示:
当文本长度较短且剩下空间正好够的时候,还是刚好能达到效果的。但是当文本长度过长的时候效果肯定是下层蓝图这样的效果,文本直接新起一行,标签后面一大段的空间就都浪费了。
所以呢,这个时候我们就结合一下旧版的设计,将最后一行的几个标签所占的宽度计算出来,然后给TextView设置一个MarginSpan,然后重新测量其宽度和高度,最后摆放的时候同最后一行标签的顶部和左端对齐布局即可。
4.代码实现(View版本)
分析完毕后我们的思路就大致定下来了,先实现流式布局,针对最后一个TextView需要重新优化再处理。
4.1.流式布局的实现
流式布局的实现,可能对大家都不陌生了,这里简要罗列下几个基础的步骤(去除了margin和padding等其他复杂的逻辑,只留下了主干代码),首先自定义MyFlowLayout继