我们可以使用 TextView
做些什么呢?
一般的文本控件可以使用 TextView
来实现,
那么,还有没有一些其他的场景,可以使用 TextView
实现呢?
本文想记录一些利用 TextView
实现的场景。
涉及到以下内容:
- 使用
drawableStart|End
实现文字 + 图标 - 使用
Span
实现「文字+图标混排」效果 - 实现带背景的文字效果
- 部分点击事件实现
- 添加原角背景 + 背景透明度设置
1. 实现文字 + 图标实现
想要实现类似这样的效果,文字 + 图标。
其实实现起来特别简单,使用一个 TextView
+ ImageView
即可。
但是,如果我们可以使用一个 View
搞定,为什么要使用两个呢?
在 TextView
中,有个属性叫做, drawableXXX
, 在 xml
中为:
// 在文字的右边放置图片
android:drawableEnd="@drawable/ic_action_like"
// 在文字的左边放置图片
android:drawableStart="@drawable/ic_action_like"
// 在文字的上边放置图片
android:drawableTop="@drawable/ic_action_like"
// 在文字的下边放置图片
android:drawableBottom="@drawable/ic_action_like"
所以,当我们想要实现上述的效果时,可以这么使用:
上述代码即可实现,文字 + 图标效果 。
android:drawablePadding
是设置该图标与文字的padding
2. 对 TextView
设置 Span
实现「文字+图标混排」效果
上述的实现,只能把图标固定的放在文字的「前、后、上、下」 这四种效果。
对于复杂的文字图标混排,就无能为力了。
那么如何实现「文字+图标混排」效果呢?
我们可以使用 ImageSpan
实现该效果。
例如,我们想要这样的效果:
在 哈哈哈123,你说不说,那我开始 balabala 了,嘿嘿嘿
中添加爱心图标,
实现代码如下:
contentView.text = "哈哈哈123,你说不说,那我开始 balabala 了,嘿嘿嘿"
val stringBuilder = SpannableString(contentView.text)
val drawable = getDrawable(R.drawable.ic_action_like)
val imageSpan = ImageSpan(drawable)
// 设置 drawable 大小,这里简单处理下
drawable!!.setBounds(0, 0, 64, 64)
stringBuilder.setSpan(imageSpan, 10, 12, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
contentView.text = stringBuilder
常见的消息中的小表情,就是利用 ImageSpan
实现的
小表情的实现,通常是利用特定的字符标志,例如
[笑脸]
,当检测到有类似这种格式[]
,会通过一套解析工具,把[笑脸]
替换成一个ImageSpan
, 从而实现小表情的效果。
3. 实现带背景的文字效果
我们想要实现的效果如下:
TextView.getText()
的返回值是 CharSequence
而 SpannableStringBuilder
实现了 CharSequence
接口 ,
表明 TextView
是可以设置 SpannableStringBuilder
的,而我们可以利用 SpannableStringBuilder
设置 span
样式,完成很多不一样的样式实现。
3.1 给部分字体添加背景
实现代码:
private fun setupLikeTextView() {
likeTextView.text = "你说是不是啊?是不是这样的,你猜一下,猜不到吧?在猜一下,哈哈哈哈,就不告诉你"
val stringBuilder = SpannableStringBuilder(likeTextView.text)
val backgroundSpan = BackgroundColorSpan(getColor(R.color.colorAccent))
val start = 3
val end = content.length
stringBuilder.setSpan(backgroundSpan, start, end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
likeTextView.text = stringBuilder
}
即可实现,likeTextView.text
从 第 3
个 字符到结尾都会添加一个带颜色的背景。
主要代码是 stringBuilder
的构建以及 likeTextView.text
的赋值。
3.2 给部分文字使用不同的颜色
实现效果如下:
hahhaah
这个文案部分, 其中的第 3 ~ 4
个字符使用不同的颜色
我们可以使用 ForegroundColorSpan
来实现不同颜色的 TextView
文本, 代码如下:
contentView.text = "hahhaah, 123, 456, 789"
val foregroundColorSpan = ForegroundColorSpan(context.resources.getColor(R.color.colorAccent))
val sb = SpannableStringBuilder(contentView.text)
sb.setSpan(foregroundColorSpan, 3, 5, SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE)
contentView.text = sb
在 Android
系统中,还有 StrikethroughSpan
, UnderlineSpan
等很多可以实现特定样式的 Span
可以供我们使用。
4. 给 TextView
设置部分文本可点击
通常在 TextView
中,如果有链接,我们需要实现点击该部分文案时会跳转到该链接的效果。
代码实现:
contentView.movementMethod = LinkMovementMethod.getInstance()
contentView.text = "哈哈哈123,后面是一个链接,可部分点击: https://www.jianshu.com/u/9d38eab6ce45"
contentView.setLinkTextColor(context.resources.getColor(R.color.blue))
val contentString = contentView.text
val start = contentString.indexOfFirst { it == ':' }
val end = contentView.text.length
val stringBuilder = SpannableString(contentView.text)
val clickableSpan = TLClickableSpan()
stringBuilder.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_INCLUSIVE)
contentView.text = stringBuilder
其中 TLClickableSpan
简单的继承了 ClickableSpan
:
class TLClickableSpan : ClickableSpan() {
override fun onClick(widget: View) {
Log.i("zc_test", "TLClickableSpan is onClick and view is $widget")
}
}
实现的效果为:
点击后的效果, log
提示为 :
2020-05-29 16:50:07.136 5602-5602/com.chendroid.learning I/zc_test: TLClickableSpan is onClick and view is com.google.android.material.textview.MaterialTextView{5773c57 VFED..CL. ...P.... 72,117-1096,223 #7f0800b7 app:id/item_content}
注意事项
代码中:contentView.movementMethod = LinkMovementMethod.getInstance() 是必须的, 如果不设置不会响应
ClickableSpan
的点击。
同时,1. 当ClickableSpan
生效时,会触发TextView
的监听事件,消费该事件;
- 当点击
TextView
非点击部分时,TextView
也会消费该事件,会导致本来应该传递给ViewGroup
的事件被TextView
拦截。
为了解决 当点击 TextView
非点击部分时, TextView
也会消费该事件, 这个问题,我们可以设置:
contentView.movementMethod = LinkMovementMethod.getInstance()
// 不可点击
contentView.isClickable = false
// 不可长按
contentView.isLongClickable = false
// 不聚焦
contentView.isFocusable = false
参考链接:https://blog.csdn.net/zhaizu/article/details/51038113
5. 添加原角背景 + 背景透明度设置
如果我们想要实现类似这样的效果:
实现图中自带透明度和圆角的「
默认
」图标。
代码如下:
//xml 中的代码
其中 @drawable/bg_blue_8
为圆角背景, 源码如下:
// bg_blue_8.xml
那么如何实现背景的透明度呢?
我们不能直接对 TextView
直接设置 TextView.setAlpha(xxx)
. 因为这样会影响到整个 TextView
的透明度,也会给字体添加上透明度。
TextView
中有单独对 background
设置的方法,我们需要这样设置:
type = view.todo_type_1
type.apply {
background.alpha = (0.08 * 255).toInt()
...
}
上述代码即可实现我们想要的效果。
注:该
UI
设计实现方案有很多种,这里只讨论如何只用一个TextView
实现。
这样实现的目的:尽可能使界面的渲染高效。避免不必要的内存浪费。
参考链接:https://www.jianshu.com/p/b5fb51529d06
6. 总结
记录了一下,日常在代码中利用 TextView
实现的一些效果,
内容不难,简单的介绍了代码实现方式。
我们还可以利用 TextView
实现很多样式的混排效果, 使用 Html
解析或者设置 Span
可以解决我们遇到的大部分问题。
这篇文章,如有错误,还请见谅,指出。
2020.5.30 by chendroid